blob: 35dc5bf01ee2ab96f62a793c466e033bf0659de4 [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) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500166 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200181
182 /*
183 * Recheck after acquire mutex. If another thread is negotiating
184 * and the server never sends an answer the socket will be closed
185 * and tcpStatus set to reconnect.
186 */
187 if (server->tcpStatus == CifsNeedReconnect) {
188 rc = -EHOSTDOWN;
189 mutex_unlock(&ses->session_mutex);
190 goto out;
191 }
192
Jeff Layton198b5682010-04-24 07:57:48 -0400193 rc = cifs_negotiate_protocol(0, ses);
194 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400195 rc = cifs_setup_session(0, ses, nls_codepage);
196
197 /* do we need to reconnect tcon? */
198 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000199 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400200 goto out;
201 }
202
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400203 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400204 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000205 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500206 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400207
208 if (rc)
209 goto out;
210
Jeff Layton9162ab22009-09-03 12:07:17 -0400211 atomic_inc(&tconInfoReconnectCount);
212
213 /* tell server Unix caps we support */
214 if (ses->capabilities & CAP_UNIX)
215 reset_cifs_unix_caps(0, tcon, NULL, NULL);
216
217 /*
218 * Removed call to reopen open files here. It is safer (and faster) to
219 * reopen files one at a time as needed in read and write.
220 *
221 * FIXME: what about file locks? don't we need to reclaim them ASAP?
222 */
223
224out:
225 /*
226 * Check if handle based operation so we know whether we can continue
227 * or not without returning to caller to reset file handle
228 */
229 switch (smb_command) {
230 case SMB_COM_READ_ANDX:
231 case SMB_COM_WRITE_ANDX:
232 case SMB_COM_CLOSE:
233 case SMB_COM_FIND_CLOSE2:
234 case SMB_COM_LOCKING_ANDX:
235 rc = -EAGAIN;
236 }
237
238 unload_nls(nls_codepage);
239 return rc;
240}
241
Steve Frenchad7a2922008-02-07 23:25:02 +0000242/* Allocate and return pointer to an SMB request buffer, and set basic
243 SMB information in the SMB header. If the return code is zero, this
244 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245static int
Steve French96daf2b2011-05-27 04:34:02 +0000246small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000247 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
Jeff Laytonf5695992010-09-29 15:27:08 -0400249 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Jeff Layton9162ab22009-09-03 12:07:17 -0400251 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000252 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return rc;
254
255 *request_buf = cifs_small_buf_get();
256 if (*request_buf == NULL) {
257 /* BB should we add a retry in here if not a writepage? */
258 return -ENOMEM;
259 }
260
Steve French63135e02007-07-17 17:34:02 +0000261 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000262 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Steve French790fe572007-07-07 19:25:05 +0000264 if (tcon != NULL)
265 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700266
Jeff Laytonf5695992010-09-29 15:27:08 -0400267 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000268}
269
Steve French12b3b8f2006-02-09 21:12:47 +0000270int
Steve French50c2f752007-07-13 00:33:32 +0000271small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000272 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000273{
274 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000275 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000276
Steve French5815449d2006-02-14 01:36:20 +0000277 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000278 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000279 return rc;
280
Steve French04fdabe2006-02-10 05:52:50 +0000281 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400282 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000283 if (ses->capabilities & CAP_UNICODE)
284 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000285 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000286 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
287
288 /* uid, tid can stay at zero as set in header assemble */
289
Steve French50c2f752007-07-13 00:33:32 +0000290 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000291 this function is used after 1st of session setup requests */
292
293 return rc;
294}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296/* If the return code is zero, this function must fill in request_buf pointer */
297static int
Steve French96daf2b2011-05-27 04:34:02 +0000298__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400299 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 *request_buf = cifs_buf_get();
302 if (*request_buf == NULL) {
303 /* BB should we add a retry in here if not a writepage? */
304 return -ENOMEM;
305 }
306 /* Although the original thought was we needed the response buf for */
307 /* potential retries of smb operations it turns out we can determine */
308 /* from the mid flags when the request buffer can be resent without */
309 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000310 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000311 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000314 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Steve French790fe572007-07-07 19:25:05 +0000316 if (tcon != NULL)
317 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700318
Jeff Laytonf5695992010-09-29 15:27:08 -0400319 return 0;
320}
321
322/* If the return code is zero, this function must fill in request_buf pointer */
323static int
Steve French96daf2b2011-05-27 04:34:02 +0000324smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400325 void **request_buf, void **response_buf)
326{
327 int rc;
328
329 rc = cifs_reconnect_tcon(tcon, smb_command);
330 if (rc)
331 return rc;
332
333 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
334}
335
336static int
Steve French96daf2b2011-05-27 04:34:02 +0000337smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400338 void **request_buf, void **response_buf)
339{
340 if (tcon->ses->need_reconnect || tcon->need_reconnect)
341 return -EHOSTDOWN;
342
343 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344}
345
Steve French50c2f752007-07-13 00:33:32 +0000346static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Jeff Layton12df83c2011-01-20 13:36:51 -0500348 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Jeff Layton12df83c2011-01-20 13:36:51 -0500350 /* check for plausible wct */
351 if (pSMB->hdr.WordCount < 10)
352 goto vt2_err;
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500355 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
356 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
357 goto vt2_err;
358
Jeff Layton12df83c2011-01-20 13:36:51 -0500359 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
360 if (total_size >= 512)
361 goto vt2_err;
362
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400363 /* check that bcc is at least as big as parms + data, and that it is
364 * less than negotiated smb buffer
365 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500366 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
367 if (total_size > get_bcc(&pSMB->hdr) ||
368 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
369 goto vt2_err;
370
371 return 0;
372vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000373 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500375 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
Jeff Layton690c5222011-01-20 13:36:51 -0500377
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400378static int
Jeff Layton3f618222013-06-12 19:52:14 -0500379decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400380{
381 int rc = 0;
382 u16 count;
383 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500384 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400385
386 count = get_bcc(&pSMBr->hdr);
387 if (count < SMB1_CLIENT_GUID_SIZE)
388 return -EIO;
389
390 spin_lock(&cifs_tcp_ses_lock);
391 if (server->srv_count > 1) {
392 spin_unlock(&cifs_tcp_ses_lock);
393 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
394 cifs_dbg(FYI, "server UID changed\n");
395 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
396 }
397 } else {
398 spin_unlock(&cifs_tcp_ses_lock);
399 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
400 }
401
402 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500403 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400404 } else {
405 count -= SMB1_CLIENT_GUID_SIZE;
406 rc = decode_negTokenInit(
407 pSMBr->u.extended_response.SecurityBlob, count, server);
408 if (rc != 1)
409 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400410 }
411
412 return 0;
413}
414
Jeff Layton9ddec562013-05-26 07:00:58 -0400415int
Jeff Layton38d77c52013-05-26 07:01:00 -0400416cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400417{
Jeff Layton50285882013-06-27 12:45:00 -0400418 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
419 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400420 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
421
422 /*
423 * Is signing required by mnt options? If not then check
424 * global_secflags to see if it is there.
425 */
426 if (!mnt_sign_required)
427 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
428 CIFSSEC_MUST_SIGN);
429
430 /*
431 * If signing is required then it's automatically enabled too,
432 * otherwise, check to see if the secflags allow it.
433 */
434 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
435 (global_secflags & CIFSSEC_MAY_SIGN);
436
437 /* If server requires signing, does client allow it? */
438 if (srv_sign_required) {
439 if (!mnt_sign_enabled) {
440 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
441 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400442 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400443 server->sign = true;
444 }
445
446 /* If client requires signing, does server allow it? */
447 if (mnt_sign_required) {
448 if (!srv_sign_enabled) {
449 cifs_dbg(VFS, "Server does not support signing!");
450 return -ENOTSUPP;
451 }
452 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400453 }
454
455 return 0;
456}
457
Jeff Layton2190eca2013-05-26 07:00:57 -0400458#ifdef CONFIG_CIFS_WEAK_PW_HASH
459static int
Jeff Layton3f618222013-06-12 19:52:14 -0500460decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400461{
462 __s16 tmp;
463 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
464
465 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
466 return -EOPNOTSUPP;
467
Jeff Layton2190eca2013-05-26 07:00:57 -0400468 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
469 server->maxReq = min_t(unsigned int,
470 le16_to_cpu(rsp->MaxMpxCount),
471 cifs_max_pending);
472 set_credits(server, server->maxReq);
473 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400474 /* even though we do not use raw we might as well set this
475 accurately, in case we ever find a need for it */
476 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
477 server->max_rw = 0xFF00;
478 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
479 } else {
480 server->max_rw = 0;/* do not need to use raw anyway */
481 server->capabilities = CAP_MPX_MODE;
482 }
483 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
484 if (tmp == -1) {
485 /* OS/2 often does not set timezone therefore
486 * we must use server time to calc time zone.
487 * Could deviate slightly from the right zone.
488 * Smallest defined timezone difference is 15 minutes
489 * (i.e. Nepal). Rounding up/down is done to match
490 * this requirement.
491 */
492 int val, seconds, remain, result;
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700493 struct timespec ts;
494 unsigned long utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400495 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
496 rsp->SrvTime.Time, 0);
497 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700498 (int)ts.tv_sec, (int)utc,
499 (int)(utc - ts.tv_sec));
500 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400501 seconds = abs(val);
502 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
503 remain = seconds % MIN_TZ_ADJ;
504 if (remain >= (MIN_TZ_ADJ / 2))
505 result += MIN_TZ_ADJ;
506 if (val < 0)
507 result = -result;
508 server->timeAdj = result;
509 } else {
510 server->timeAdj = (int)tmp;
511 server->timeAdj *= 60; /* also in seconds */
512 }
513 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
514
515
516 /* BB get server time for time conversions and add
517 code to use it and timezone since this is not UTC */
518
519 if (rsp->EncryptionKeyLength ==
520 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
521 memcpy(server->cryptkey, rsp->EncryptionKey,
522 CIFS_CRYPTO_KEY_SIZE);
523 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
524 return -EIO; /* need cryptkey unless plain text */
525 }
526
527 cifs_dbg(FYI, "LANMAN negotiated\n");
528 return 0;
529}
530#else
531static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500532decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400533{
534 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
535 return -EOPNOTSUPP;
536}
537#endif
538
Jeff Layton91934002013-05-26 07:00:58 -0400539static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500540should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400541{
Jeff Layton3f618222013-06-12 19:52:14 -0500542 switch (sectype) {
543 case RawNTLMSSP:
544 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400545 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500546 case Unspecified:
547 if (global_secflags &
548 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
549 return true;
550 /* Fallthrough */
551 default:
552 return false;
553 }
Jeff Layton91934002013-05-26 07:00:58 -0400554}
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400557CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
559 NEGOTIATE_REQ *pSMB;
560 NEGOTIATE_RSP *pSMBr;
561 int rc = 0;
562 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000563 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400564 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 u16 count;
566
Jeff Layton3534b852013-05-24 07:41:01 -0400567 if (!server) {
568 WARN(1, "%s: server is NULL!\n", __func__);
569 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
Jeff Layton3534b852013-05-24 07:41:01 -0400571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
573 (void **) &pSMB, (void **) &pSMBr);
574 if (rc)
575 return rc;
Steve French750d1152006-06-27 06:28:30 +0000576
Pavel Shilovsky88257362012-05-23 14:01:59 +0400577 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000578 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000579
Jeff Layton3f618222013-06-12 19:52:14 -0500580 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400581 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000582 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
583 }
Steve French50c2f752007-07-13 00:33:32 +0000584
Steve French39798772006-05-31 22:40:51 +0000585 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000586 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000587 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
588 count += strlen(protocols[i].name) + 1;
589 /* null at end of source and target buffers anyway */
590 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000591 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 pSMB->ByteCount = cpu_to_le16(count);
593
594 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
595 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000596 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000597 goto neg_err_exit;
598
Jeff Layton9bf67e52010-04-24 07:57:46 -0400599 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500600 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000601 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400602 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000603 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000604 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000605 could not negotiate a common dialect */
606 rc = -EOPNOTSUPP;
607 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000608 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400609 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500610 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400611 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000612 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000613 /* unknown wct */
614 rc = -EOPNOTSUPP;
615 goto neg_err_exit;
616 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400617 /* else wct == 17, NTLM or better */
618
Steve French96daf2b2011-05-27 04:34:02 +0000619 server->sec_mode = pSMBr->SecurityMode;
620 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500621 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000622
Steve French254e55e2006-06-04 05:53:15 +0000623 /* one byte, so no need to convert this or EncryptionKeyLen from
624 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300625 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
626 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400627 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000628 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400629 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000630 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500631 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000632 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000633 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
634 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400635
Jeff Laytone598d1d82013-05-26 07:00:59 -0400636 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
637 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500638 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000639 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100640 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
641 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400642 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500643 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400644 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000645 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400646 } else {
647 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000648 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400649 }
Steve French254e55e2006-06-04 05:53:15 +0000650
651signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400652 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400653 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000654neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700655 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000656
Joe Perchesf96637b2013-05-04 22:12:25 -0500657 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 return rc;
659}
660
661int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400662CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
664 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Joe Perchesf96637b2013-05-04 22:12:25 -0500667 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500668
669 /* BB: do we need to check this? These should never be NULL. */
670 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
671 return -EIO;
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500674 * No need to return error on this operation if tid invalidated and
675 * closed on server already e.g. due to tcp session crashing. Also,
676 * the tcon is no longer on the list, so no need to take lock before
677 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 */
Steve French268875b2009-06-25 00:29:21 +0000679 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000680 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Steve French50c2f752007-07-13 00:33:32 +0000682 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700683 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500684 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return rc;
Steve French133672e2007-11-13 22:41:37 +0000686
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400687 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700688 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500690 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Steve French50c2f752007-07-13 00:33:32 +0000692 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500693 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (rc == -EAGAIN)
695 rc = 0;
696
697 return rc;
698}
699
Jeff Layton766fdbb2011-01-11 07:24:21 -0500700/*
701 * This is a no-op for now. We're not really interested in the reply, but
702 * rather in the fact that the server sent one and that server->lstrp
703 * gets updated.
704 *
705 * FIXME: maybe we should consider checking that the reply matches request?
706 */
707static void
708cifs_echo_callback(struct mid_q_entry *mid)
709{
710 struct TCP_Server_Info *server = mid->callback_data;
711
712 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400713 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500714}
715
716int
717CIFSSMBEcho(struct TCP_Server_Info *server)
718{
719 ECHO_REQ *smb;
720 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800721 struct kvec iov[2];
722 struct smb_rqst rqst = { .rq_iov = iov,
723 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500724
Joe Perchesf96637b2013-05-04 22:12:25 -0500725 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500726
727 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
728 if (rc)
729 return rc;
730
Steve French26c9cb62017-05-02 13:35:20 -0500731 if (server->capabilities & CAP_UNICODE)
732 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
733
Jeff Layton766fdbb2011-01-11 07:24:21 -0500734 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000735 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500736 smb->hdr.WordCount = 1;
737 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400738 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500739 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000740 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800741
742 iov[0].iov_len = 4;
743 iov[0].iov_base = smb;
744 iov[1].iov_len = get_rfc1002_length(smb);
745 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800747 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400748 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500749 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500750 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500751
752 cifs_small_buf_release(smb);
753
754 return rc;
755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400758CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 LOGOFF_ANDX_REQ *pSMB;
761 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Joe Perchesf96637b2013-05-04 22:12:25 -0500763 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500764
765 /*
766 * BB: do we need to check validity of ses and server? They should
767 * always be valid since we have an active reference. If not, that
768 * should probably be a BUG()
769 */
770 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return -EIO;
772
Steve Frenchd7b619c2010-02-25 05:36:46 +0000773 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000774 if (ses->need_reconnect)
775 goto session_already_dead; /* no need to send SMBlogoff if uid
776 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
778 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000779 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return rc;
781 }
782
Pavel Shilovsky88257362012-05-23 14:01:59 +0400783 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700784
Jeff Layton38d77c52013-05-26 07:01:00 -0400785 if (ses->server->sign)
786 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 pSMB->hdr.Uid = ses->Suid;
789
790 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400791 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700792 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000793session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000794 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000797 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 error */
799 if (rc == -EAGAIN)
800 rc = 0;
801 return rc;
802}
803
804int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400805CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
806 const char *fileName, __u16 type,
807 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000808{
809 TRANSACTION2_SPI_REQ *pSMB = NULL;
810 TRANSACTION2_SPI_RSP *pSMBr = NULL;
811 struct unlink_psx_rq *pRqD;
812 int name_len;
813 int rc = 0;
814 int bytes_returned = 0;
815 __u16 params, param_offset, offset, byte_count;
816
Joe Perchesf96637b2013-05-04 22:12:25 -0500817 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000818PsxDelete:
819 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
820 (void **) &pSMBr);
821 if (rc)
822 return rc;
823
824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
825 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600826 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
827 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000828 name_len++; /* trailing null */
829 name_len *= 2;
830 } else { /* BB add path length overrun check */
831 name_len = strnlen(fileName, PATH_MAX);
832 name_len++; /* trailing null */
833 strncpy(pSMB->FileName, fileName, name_len);
834 }
835
836 params = 6 + name_len;
837 pSMB->MaxParameterCount = cpu_to_le16(2);
838 pSMB->MaxDataCount = 0; /* BB double check this with jra */
839 pSMB->MaxSetupCount = 0;
840 pSMB->Reserved = 0;
841 pSMB->Flags = 0;
842 pSMB->Timeout = 0;
843 pSMB->Reserved2 = 0;
844 param_offset = offsetof(struct smb_com_transaction2_spi_req,
845 InformationLevel) - 4;
846 offset = param_offset + params;
847
848 /* Setup pointer to Request Data (inode type) */
849 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
850 pRqD->type = cpu_to_le16(type);
851 pSMB->ParameterOffset = cpu_to_le16(param_offset);
852 pSMB->DataOffset = cpu_to_le16(offset);
853 pSMB->SetupCount = 1;
854 pSMB->Reserved3 = 0;
855 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
856 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
857
858 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
859 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
860 pSMB->ParameterCount = cpu_to_le16(params);
861 pSMB->TotalParameterCount = pSMB->ParameterCount;
862 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
863 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000864 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000865 pSMB->ByteCount = cpu_to_le16(byte_count);
866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000868 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500869 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000870 cifs_buf_release(pSMB);
871
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400872 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000873
874 if (rc == -EAGAIN)
875 goto PsxDelete;
876
877 return rc;
878}
879
880int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700881CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
882 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 DELETE_FILE_REQ *pSMB = NULL;
885 DELETE_FILE_RSP *pSMBr = NULL;
886 int rc = 0;
887 int bytes_returned;
888 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500889 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891DelFileRetry:
892 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
893 (void **) &pSMBr);
894 if (rc)
895 return rc;
896
897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700898 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
899 PATH_MAX, cifs_sb->local_nls,
900 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len++; /* trailing null */
902 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700903 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700906 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 pSMB->SearchAttributes =
909 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
910 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000911 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 pSMB->ByteCount = cpu_to_le16(name_len + 1);
913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400915 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000916 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500917 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 cifs_buf_release(pSMB);
920 if (rc == -EAGAIN)
921 goto DelFileRetry;
922
923 return rc;
924}
925
926int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400927CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
928 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 DELETE_DIRECTORY_REQ *pSMB = NULL;
931 DELETE_DIRECTORY_RSP *pSMBr = NULL;
932 int rc = 0;
933 int bytes_returned;
934 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500935 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Joe Perchesf96637b2013-05-04 22:12:25 -0500937 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938RmDirRetry:
939 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
940 (void **) &pSMBr);
941 if (rc)
942 return rc;
943
944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400945 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
946 PATH_MAX, cifs_sb->local_nls,
947 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 name_len++; /* trailing null */
949 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700950 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400953 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 }
955
956 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000957 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 pSMB->ByteCount = cpu_to_le16(name_len + 1);
959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400961 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000962 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500963 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 cifs_buf_release(pSMB);
966 if (rc == -EAGAIN)
967 goto RmDirRetry;
968 return rc;
969}
970
971int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300972CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
973 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
975 int rc = 0;
976 CREATE_DIRECTORY_REQ *pSMB = NULL;
977 CREATE_DIRECTORY_RSP *pSMBr = NULL;
978 int bytes_returned;
979 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500980 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Joe Perchesf96637b2013-05-04 22:12:25 -0500982 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983MkDirRetry:
984 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
985 (void **) &pSMBr);
986 if (rc)
987 return rc;
988
989 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600990 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300991 PATH_MAX, cifs_sb->local_nls,
992 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 name_len++; /* trailing null */
994 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700995 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 name_len = strnlen(name, PATH_MAX);
997 name_len++; /* trailing null */
998 strncpy(pSMB->DirName, name, name_len);
999 }
1000
1001 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001002 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001006 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001008 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 cifs_buf_release(pSMB);
1011 if (rc == -EAGAIN)
1012 goto MkDirRetry;
1013 return rc;
1014}
1015
Steve French2dd29d32007-04-23 22:07:35 +00001016int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001017CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1018 __u32 posix_flags, __u64 mode, __u16 *netfid,
1019 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1020 const char *name, const struct nls_table *nls_codepage,
1021 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001022{
1023 TRANSACTION2_SPI_REQ *pSMB = NULL;
1024 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1025 int name_len;
1026 int rc = 0;
1027 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001028 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001029 OPEN_PSX_REQ *pdata;
1030 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001031
Joe Perchesf96637b2013-05-04 22:12:25 -05001032 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001033PsxCreat:
1034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1035 (void **) &pSMBr);
1036 if (rc)
1037 return rc;
1038
1039 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1040 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001041 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1042 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001043 name_len++; /* trailing null */
1044 name_len *= 2;
1045 } else { /* BB improve the check for buffer overruns BB */
1046 name_len = strnlen(name, PATH_MAX);
1047 name_len++; /* trailing null */
1048 strncpy(pSMB->FileName, name, name_len);
1049 }
1050
1051 params = 6 + name_len;
1052 count = sizeof(OPEN_PSX_REQ);
1053 pSMB->MaxParameterCount = cpu_to_le16(2);
1054 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1055 pSMB->MaxSetupCount = 0;
1056 pSMB->Reserved = 0;
1057 pSMB->Flags = 0;
1058 pSMB->Timeout = 0;
1059 pSMB->Reserved2 = 0;
1060 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001061 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001062 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001063 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001064 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001065 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001066 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001067 pdata->OpenFlags = cpu_to_le32(*pOplock);
1068 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1069 pSMB->DataOffset = cpu_to_le16(offset);
1070 pSMB->SetupCount = 1;
1071 pSMB->Reserved3 = 0;
1072 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1073 byte_count = 3 /* pad */ + params + count;
1074
1075 pSMB->DataCount = cpu_to_le16(count);
1076 pSMB->ParameterCount = cpu_to_le16(params);
1077 pSMB->TotalDataCount = pSMB->DataCount;
1078 pSMB->TotalParameterCount = pSMB->ParameterCount;
1079 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1080 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001081 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001082 pSMB->ByteCount = cpu_to_le16(byte_count);
1083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1085 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001086 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001087 goto psx_create_err;
1088 }
1089
Joe Perchesf96637b2013-05-04 22:12:25 -05001090 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1092
Jeff Layton820a8032011-05-04 08:05:26 -04001093 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = -EIO; /* bad smb */
1095 goto psx_create_err;
1096 }
1097
1098 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001099 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001100 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001101
Steve French2dd29d32007-04-23 22:07:35 +00001102 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001103 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001104 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1105 /* Let caller know file was created so we can set the mode. */
1106 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001107 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001108 *pOplock |= CIFS_CREATE_ACTION;
1109 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001110 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1111 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001112 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001114 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001115 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001116 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001117 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001118 goto psx_create_err;
1119 }
Steve French50c2f752007-07-13 00:33:32 +00001120 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001121 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001122 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001123 }
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125psx_create_err:
1126 cifs_buf_release(pSMB);
1127
Steve French65bc98b2009-07-10 15:27:25 +00001128 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001129 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001130 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001131 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001163 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
Jeff Layton35fc37d2008-05-14 10:22:03 -07001169static int
1170access_flags_to_smbopen_mode(const int access_flags)
1171{
1172 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1173
1174 if (masked_flags == GENERIC_READ)
1175 return SMBOPEN_READ;
1176 else if (masked_flags == GENERIC_WRITE)
1177 return SMBOPEN_WRITE;
1178
1179 /* just go for read/write */
1180 return SMBOPEN_READWRITE;
1181}
1182
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001184SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001186 const int access_flags, const int create_options, __u16 *netfid,
1187 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 const struct nls_table *nls_codepage, int remap)
1189{
1190 int rc = -EACCES;
1191 OPENX_REQ *pSMB = NULL;
1192 OPENX_RSP *pSMBr = NULL;
1193 int bytes_returned;
1194 int name_len;
1195 __u16 count;
1196
1197OldOpenRetry:
1198 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199 (void **) &pSMBr);
1200 if (rc)
1201 return rc;
1202
1203 pSMB->AndXCommand = 0xFF; /* none */
1204
1205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206 count = 1; /* account for one byte pad to word boundary */
1207 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001208 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1209 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 name_len++; /* trailing null */
1211 name_len *= 2;
1212 } else { /* BB improve check for buffer overruns BB */
1213 count = 0; /* no pad */
1214 name_len = strnlen(fileName, PATH_MAX);
1215 name_len++; /* trailing null */
1216 strncpy(pSMB->fileName, fileName, name_len);
1217 }
1218 if (*pOplock & REQ_OPLOCK)
1219 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001222
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001224 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226 /* set file as system file if special file such
1227 as fifo and server expecting SFU style and
1228 no Unix extensions */
1229
Steve French790fe572007-07-07 19:25:05 +00001230 if (create_options & CREATE_OPTION_SPECIAL)
1231 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001232 else /* BB FIXME BB */
1233 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
Jeff Layton67750fb2008-05-09 22:28:02 +00001235 if (create_options & CREATE_OPTION_READONLY)
1236 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
1238 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001239/* pSMB->CreateOptions = cpu_to_le32(create_options &
1240 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001242
1243 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001244 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001246 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247
1248 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001250 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001251 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001253 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 } else {
1255 /* BB verify if wct == 15 */
1256
Steve French582d21e2008-05-13 04:54:12 +00001257/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258
1259 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1260 /* Let caller know file was created so we can set the mode. */
1261 /* Do we care about the CreateAction in any other cases? */
1262 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001263/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 *pOplock |= CIFS_CREATE_ACTION; */
1265 /* BB FIXME END */
1266
Steve French790fe572007-07-07 19:25:05 +00001267 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1269 pfile_info->LastAccessTime = 0; /* BB fixme */
1270 pfile_info->LastWriteTime = 0; /* BB fixme */
1271 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001272 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001273 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001275 pfile_info->AllocationSize =
1276 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1277 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001279 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001280 }
1281 }
1282
1283 cifs_buf_release(pSMB);
1284 if (rc == -EAGAIN)
1285 goto OldOpenRetry;
1286 return rc;
1287}
1288
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001290CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1291 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292{
1293 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001294 OPEN_REQ *req = NULL;
1295 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 int bytes_returned;
1297 int name_len;
1298 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001299 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1300 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001301 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001302 const struct nls_table *nls = cifs_sb->local_nls;
1303 int create_options = oparms->create_options;
1304 int desired_access = oparms->desired_access;
1305 int disposition = oparms->disposition;
1306 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
1308openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001309 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1310 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (rc)
1312 return rc;
1313
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001314 /* no commands go after this */
1315 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001317 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1318 /* account for one byte pad to word boundary */
1319 count = 1;
1320 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1321 path, PATH_MAX, nls, remap);
1322 /* trailing null */
1323 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001325 req->NameLength = cpu_to_le16(name_len);
1326 } else {
1327 /* BB improve check for buffer overruns BB */
1328 /* no pad */
1329 count = 0;
1330 name_len = strnlen(path, PATH_MAX);
1331 /* trailing null */
1332 name_len++;
1333 req->NameLength = cpu_to_le16(name_len);
1334 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001336
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001337 if (*oplock & REQ_OPLOCK)
1338 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1339 else if (*oplock & REQ_BATCHOPLOCK)
1340 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1341
1342 req->DesiredAccess = cpu_to_le32(desired_access);
1343 req->AllocationSize = 0;
1344
1345 /*
1346 * Set file as system file if special file such as fifo and server
1347 * expecting SFU style and no Unix extensions.
1348 */
1349 if (create_options & CREATE_OPTION_SPECIAL)
1350 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1351 else
1352 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1353
1354 /*
1355 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1356 * sensitive checks for other servers such as Samba.
1357 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001359 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Jeff Layton67750fb2008-05-09 22:28:02 +00001361 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001362 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001363
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001364 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1365 req->CreateDisposition = cpu_to_le32(disposition);
1366 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1367
Steve French09d1db52005-04-28 22:41:08 -07001368 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001369 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1370 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001373 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001375 req->ByteCount = cpu_to_le16(count);
1376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1377 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001378 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001380 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001381 cifs_buf_release(req);
1382 if (rc == -EAGAIN)
1383 goto openRetry;
1384 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001386
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001387 /* 1 byte no need to le_to_cpu */
1388 *oplock = rsp->OplockLevel;
1389 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001390 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001391
1392 /* Let caller know file was created so we can set the mode. */
1393 /* Do we care about the CreateAction in any other cases? */
1394 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1395 *oplock |= CIFS_CREATE_ACTION;
1396
1397 if (buf) {
1398 /* copy from CreationTime to Attributes */
1399 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1400 /* the file_info buf is endian converted by caller */
1401 buf->AllocationSize = rsp->AllocationSize;
1402 buf->EndOfFile = rsp->EndOfFile;
1403 buf->NumberOfLinks = cpu_to_le32(1);
1404 buf->DeletePending = 0;
1405 }
1406
1407 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 return rc;
1409}
1410
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001411/*
1412 * Discard any remaining data in the current SMB. To do this, we borrow the
1413 * current bigbuf.
1414 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001415int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001416cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001417{
Pavel Shilovsky350be252017-04-10 10:31:33 -07001418 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001419 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001420
1421 while (remaining > 0) {
1422 int length;
1423
1424 length = cifs_read_from_socket(server, server->bigbuf,
1425 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001426 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427 if (length < 0)
1428 return length;
1429 server->total_read += length;
1430 remaining -= length;
1431 }
1432
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001433 return 0;
1434}
1435
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001436static int
1437cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1438{
1439 int length;
1440 struct cifs_readdata *rdata = mid->callback_data;
1441
Pavel Shilovsky350be252017-04-10 10:31:33 -07001442 length = cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001443 dequeue_mid(mid, rdata->result);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001444 mid->resp_buf = server->smallbuf;
1445 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001446 return length;
1447}
1448
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001449int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1451{
1452 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001453 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001454 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001455 char *buf = server->smallbuf;
1456 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457
Joe Perchesf96637b2013-05-04 22:12:25 -05001458 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1459 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001460
1461 /*
1462 * read the rest of READ_RSP header (sans Data array), or whatever we
1463 * can if there's not enough data. At this point, we've read down to
1464 * the Mid.
1465 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001466 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001467 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001468
Al Viroa6137302016-01-09 19:37:16 -05001469 length = cifs_read_from_socket(server,
1470 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001471 if (length < 0)
1472 return length;
1473 server->total_read += length;
1474
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001475 if (server->ops->is_session_expired &&
1476 server->ops->is_session_expired(buf)) {
1477 cifs_reconnect(server);
1478 wake_up(&server->response_q);
1479 return -1;
1480 }
1481
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001482 if (server->ops->is_status_pending &&
1483 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001484 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001485 return -1;
1486 }
1487
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001488 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001489 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001490 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001491 cifs_dbg(FYI, "%s: server returned error %d\n",
1492 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001493 return cifs_readv_discard(server, mid);
1494 }
1495
1496 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001497 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001498 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1499 __func__, server->total_read,
1500 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001501 rdata->result = -EIO;
1502 return cifs_readv_discard(server, mid);
1503 }
1504
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001505 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506 if (data_offset < server->total_read) {
1507 /*
1508 * win2k8 sometimes sends an offset of 0 when the read
1509 * is beyond the EOF. Treat it as if the data starts just after
1510 * the header.
1511 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001512 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1513 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514 data_offset = server->total_read;
1515 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1516 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001517 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1518 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519 rdata->result = -EIO;
1520 return cifs_readv_discard(server, mid);
1521 }
1522
Joe Perchesf96637b2013-05-04 22:12:25 -05001523 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1524 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001525
1526 len = data_offset - server->total_read;
1527 if (len > 0) {
1528 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001529 length = cifs_read_from_socket(server,
1530 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531 if (length < 0)
1532 return length;
1533 server->total_read += length;
1534 }
1535
1536 /* set up first iov for signature check */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001537 rdata->iov[0].iov_base = buf;
1538 rdata->iov[0].iov_len = 4;
1539 rdata->iov[1].iov_base = buf + 4;
1540 rdata->iov[1].iov_len = server->total_read - 4;
1541 cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
1542 rdata->iov[0].iov_base, server->total_read);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543
1544 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001545 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001546 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547 /* data_len is corrupt -- discard frame */
1548 rdata->result = -EIO;
1549 return cifs_readv_discard(server, mid);
1550 }
1551
Jeff Layton8321fec2012-09-19 06:22:32 -07001552 length = rdata->read_into_pages(server, rdata, data_len);
1553 if (length < 0)
1554 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001555
Jeff Layton8321fec2012-09-19 06:22:32 -07001556 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557
Joe Perchesf96637b2013-05-04 22:12:25 -05001558 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1559 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560
1561 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001562 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001563 return cifs_readv_discard(server, mid);
1564
1565 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001566 mid->resp_buf = server->smallbuf;
1567 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001568 return length;
1569}
1570
1571static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572cifs_readv_callback(struct mid_q_entry *mid)
1573{
1574 struct cifs_readdata *rdata = mid->callback_data;
1575 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1576 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001577 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1578 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001579 .rq_pages = rdata->pages,
1580 .rq_npages = rdata->nr_pages,
1581 .rq_pagesz = rdata->pagesz,
1582 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001583
Joe Perchesf96637b2013-05-04 22:12:25 -05001584 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1585 __func__, mid->mid, mid->mid_state, rdata->result,
1586 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001588 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001589 case MID_RESPONSE_RECEIVED:
1590 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001591 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001592 int rc = 0;
1593
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001594 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001595 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001596 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001597 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1598 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001599 }
1600 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001601 task_io_account_read(rdata->got_bytes);
1602 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001603 break;
1604 case MID_REQUEST_SUBMITTED:
1605 case MID_RETRY_NEEDED:
1606 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001607 if (server->sign && rdata->got_bytes)
1608 /* reset bytes number since we can not check a sign */
1609 rdata->got_bytes = 0;
1610 /* FIXME: should this be counted toward the initiating task? */
1611 task_io_account_read(rdata->got_bytes);
1612 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001613 break;
1614 default:
1615 rdata->result = -EIO;
1616 }
1617
Jeff Laytonda472fc2012-03-23 14:40:53 -04001618 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001619 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001620 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001621}
1622
1623/* cifs_async_readv - send an async write, and set up mid to handle result */
1624int
1625cifs_async_readv(struct cifs_readdata *rdata)
1626{
1627 int rc;
1628 READ_REQ *smb = NULL;
1629 int wct;
1630 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001631 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1632 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001633
Joe Perchesf96637b2013-05-04 22:12:25 -05001634 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1635 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001636
1637 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1638 wct = 12;
1639 else {
1640 wct = 10; /* old style read */
1641 if ((rdata->offset >> 32) > 0) {
1642 /* can not handle this big offset for old */
1643 return -EIO;
1644 }
1645 }
1646
1647 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1648 if (rc)
1649 return rc;
1650
1651 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1652 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1653
1654 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001655 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001656 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1657 if (wct == 12)
1658 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1659 smb->Remaining = 0;
1660 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1661 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1662 if (wct == 12)
1663 smb->ByteCount = 0;
1664 else {
1665 /* old style read */
1666 struct smb_com_readx_req *smbr =
1667 (struct smb_com_readx_req *)smb;
1668 smbr->ByteCount = 0;
1669 }
1670
1671 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001672 rdata->iov[0].iov_base = smb;
1673 rdata->iov[0].iov_len = 4;
1674 rdata->iov[1].iov_base = (char *)smb + 4;
1675 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001676
Jeff Layton6993f742012-05-16 07:13:17 -04001677 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001678 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001679 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001680
1681 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001682 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001683 else
1684 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001685
1686 cifs_small_buf_release(smb);
1687 return rc;
1688}
1689
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001691CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1692 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
1694 int rc = -EACCES;
1695 READ_REQ *pSMB = NULL;
1696 READ_RSP *pSMBr = NULL;
1697 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001698 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001699 int resp_buf_type = 0;
1700 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001701 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001702 __u32 pid = io_parms->pid;
1703 __u16 netfid = io_parms->netfid;
1704 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001705 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001706 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
Joe Perchesf96637b2013-05-04 22:12:25 -05001708 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001709 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001710 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001711 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001712 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001713 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001714 /* can not handle this big offset for old */
1715 return -EIO;
1716 }
1717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001720 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 if (rc)
1722 return rc;
1723
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001724 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1725 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 /* tcon and ses pointer are checked in smb_init */
1728 if (tcon->ses->server == NULL)
1729 return -ECONNABORTED;
1730
Steve Frenchec637e32005-12-12 20:53:18 -08001731 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001733 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001734 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001735 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 pSMB->Remaining = 0;
1738 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1739 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001740 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001741 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1742 else {
1743 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001744 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001745 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001746 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001747 }
Steve Frenchec637e32005-12-12 20:53:18 -08001748
1749 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001750 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001751 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1752 CIFS_LOG_ERROR, &rsp_iov);
1753 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001754 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001755 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001757 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 } else {
1759 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1760 data_length = data_length << 16;
1761 data_length += le16_to_cpu(pSMBr->DataLength);
1762 *nbytes = data_length;
1763
1764 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001765 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001767 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001768 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 rc = -EIO;
1770 *nbytes = 0;
1771 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001772 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001773 le16_to_cpu(pSMBr->DataOffset);
1774/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001775 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001776 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001777 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001778 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001779 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 }
1781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Steve French790fe572007-07-07 19:25:05 +00001783 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001784 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001785 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001786 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001787 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001788 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001789 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001790 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001791 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001792 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001793
1794 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 since file handle passed in no longer valid */
1796 return rc;
1797}
1798
Steve Frenchec637e32005-12-12 20:53:18 -08001799
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001801CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001802 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803{
1804 int rc = -EACCES;
1805 WRITE_REQ *pSMB = NULL;
1806 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001807 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 __u32 bytes_sent;
1809 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001810 __u32 pid = io_parms->pid;
1811 __u16 netfid = io_parms->netfid;
1812 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001813 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001814 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
Steve Frencha24e2d72010-04-03 17:20:21 +00001816 *nbytes = 0;
1817
Joe Perchesf96637b2013-05-04 22:12:25 -05001818 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001819 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001820 return -ECONNABORTED;
1821
Steve French790fe572007-07-07 19:25:05 +00001822 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001823 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001824 else {
Steve French1c955182005-08-30 20:58:07 -07001825 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001826 if ((offset >> 32) > 0) {
1827 /* can not handle big offset for old srv */
1828 return -EIO;
1829 }
1830 }
Steve French1c955182005-08-30 20:58:07 -07001831
1832 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 (void **) &pSMBr);
1834 if (rc)
1835 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001836
1837 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1838 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 /* tcon and ses pointer are checked in smb_init */
1841 if (tcon->ses->server == NULL)
1842 return -ECONNABORTED;
1843
1844 pSMB->AndXCommand = 0xFF; /* none */
1845 pSMB->Fid = netfid;
1846 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001847 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001848 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001849
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 pSMB->Reserved = 0xFFFFFFFF;
1851 pSMB->WriteMode = 0;
1852 pSMB->Remaining = 0;
1853
Steve French50c2f752007-07-13 00:33:32 +00001854 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 can send more if LARGE_WRITE_X capability returned by the server and if
1856 our buffer is big enough or if we convert to iovecs on socket writes
1857 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001858 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1860 } else {
1861 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1862 & ~0xFF;
1863 }
1864
1865 if (bytes_sent > count)
1866 bytes_sent = count;
1867 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001868 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001869 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001870 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001871 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 /* No buffer */
1873 cifs_buf_release(pSMB);
1874 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001875 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001876 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001877 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001878 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001879 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1882 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001883 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001884
Steve French790fe572007-07-07 19:25:05 +00001885 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001886 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001887 else { /* old style write has byte count 4 bytes earlier
1888 so 4 bytes pad */
1889 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001890 (struct smb_com_writex_req *)pSMB;
1891 pSMBW->ByteCount = cpu_to_le16(byte_count);
1892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
1894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001896 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001898 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 } else {
1900 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1901 *nbytes = (*nbytes) << 16;
1902 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301903
1904 /*
1905 * Mask off high 16 bits when bytes written as returned by the
1906 * server is greater than bytes requested by the client. Some
1907 * OS/2 servers are known to set incorrect CountHigh values.
1908 */
1909 if (*nbytes > count)
1910 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 }
1912
1913 cifs_buf_release(pSMB);
1914
Steve French50c2f752007-07-13 00:33:32 +00001915 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 since file handle passed in no longer valid */
1917
1918 return rc;
1919}
1920
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001921void
1922cifs_writedata_release(struct kref *refcount)
1923{
1924 struct cifs_writedata *wdata = container_of(refcount,
1925 struct cifs_writedata, refcount);
1926
1927 if (wdata->cfile)
1928 cifsFileInfo_put(wdata->cfile);
1929
1930 kfree(wdata);
1931}
1932
1933/*
1934 * Write failed with a retryable error. Resend the write request. It's also
1935 * possible that the page was redirtied so re-clean the page.
1936 */
1937static void
1938cifs_writev_requeue(struct cifs_writedata *wdata)
1939{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001940 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001941 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001942 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001943 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001944
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001945 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1946 i = 0;
1947 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001948 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001949 struct cifs_writedata *wdata2;
1950 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001951
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001952 wsize = server->ops->wp_retry_size(inode);
1953 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001954 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001955 if (!nr_pages) {
1956 rc = -ENOTSUPP;
1957 break;
1958 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001959 cur_len = nr_pages * PAGE_SIZE;
1960 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001961 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001962 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001963 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001964 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001965 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001966
1967 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1968 if (!wdata2) {
1969 rc = -ENOMEM;
1970 break;
1971 }
1972
1973 for (j = 0; j < nr_pages; j++) {
1974 wdata2->pages[j] = wdata->pages[i + j];
1975 lock_page(wdata2->pages[j]);
1976 clear_page_dirty_for_io(wdata2->pages[j]);
1977 }
1978
1979 wdata2->sync_mode = wdata->sync_mode;
1980 wdata2->nr_pages = nr_pages;
1981 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001982 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001983 wdata2->tailsz = tailsz;
1984 wdata2->bytes = cur_len;
1985
1986 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1987 if (!wdata2->cfile) {
1988 cifs_dbg(VFS, "No writable handles for inode\n");
1989 rc = -EBADF;
1990 break;
1991 }
1992 wdata2->pid = wdata2->cfile->pid;
1993 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1994
1995 for (j = 0; j < nr_pages; j++) {
1996 unlock_page(wdata2->pages[j]);
1997 if (rc != 0 && rc != -EAGAIN) {
1998 SetPageError(wdata2->pages[j]);
1999 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002000 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002001 }
2002 }
2003
2004 if (rc) {
2005 kref_put(&wdata2->refcount, cifs_writedata_release);
2006 if (rc == -EAGAIN)
2007 continue;
2008 break;
2009 }
2010
2011 rest_len -= cur_len;
2012 i += nr_pages;
2013 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002014
2015 mapping_set_error(inode->i_mapping, rc);
2016 kref_put(&wdata->refcount, cifs_writedata_release);
2017}
2018
Jeff Laytonc2e87642012-03-23 14:40:55 -04002019void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002020cifs_writev_complete(struct work_struct *work)
2021{
2022 struct cifs_writedata *wdata = container_of(work,
2023 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002024 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002025 int i = 0;
2026
2027 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002028 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002029 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002030 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002031 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2032 wdata->bytes);
2033 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2034 return cifs_writev_requeue(wdata);
2035
2036 for (i = 0; i < wdata->nr_pages; i++) {
2037 struct page *page = wdata->pages[i];
2038 if (wdata->result == -EAGAIN)
2039 __set_page_dirty_nobuffers(page);
2040 else if (wdata->result < 0)
2041 SetPageError(page);
2042 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002043 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002044 }
2045 if (wdata->result != -EAGAIN)
2046 mapping_set_error(inode->i_mapping, wdata->result);
2047 kref_put(&wdata->refcount, cifs_writedata_release);
2048}
2049
2050struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002051cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052{
2053 struct cifs_writedata *wdata;
2054
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002055 /* writedata + number of page pointers */
2056 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002057 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002058 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002059 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002060 INIT_LIST_HEAD(&wdata->list);
2061 init_completion(&wdata->done);
2062 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002063 }
2064 return wdata;
2065}
2066
2067/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002068 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002069 * workqueue completion task.
2070 */
2071static void
2072cifs_writev_callback(struct mid_q_entry *mid)
2073{
2074 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002075 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076 unsigned int written;
2077 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2078
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002079 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080 case MID_RESPONSE_RECEIVED:
2081 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2082 if (wdata->result != 0)
2083 break;
2084
2085 written = le16_to_cpu(smb->CountHigh);
2086 written <<= 16;
2087 written += le16_to_cpu(smb->Count);
2088 /*
2089 * Mask off high 16 bits when bytes written as returned
2090 * by the server is greater than bytes requested by the
2091 * client. OS/2 servers are known to set incorrect
2092 * CountHigh values.
2093 */
2094 if (written > wdata->bytes)
2095 written &= 0xFFFF;
2096
2097 if (written < wdata->bytes)
2098 wdata->result = -ENOSPC;
2099 else
2100 wdata->bytes = written;
2101 break;
2102 case MID_REQUEST_SUBMITTED:
2103 case MID_RETRY_NEEDED:
2104 wdata->result = -EAGAIN;
2105 break;
2106 default:
2107 wdata->result = -EIO;
2108 break;
2109 }
2110
Jeff Laytonda472fc2012-03-23 14:40:53 -04002111 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002112 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002113 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002114}
2115
2116/* cifs_async_writev - send an async write, and set up mid to handle result */
2117int
Steve French4a5c80d2014-02-07 20:45:12 -06002118cifs_async_writev(struct cifs_writedata *wdata,
2119 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002120{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002121 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122 WRITE_REQ *smb = NULL;
2123 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002124 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002125 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002126 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002127
2128 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2129 wct = 14;
2130 } else {
2131 wct = 12;
2132 if (wdata->offset >> 32 > 0) {
2133 /* can not handle big offset for old srv */
2134 return -EIO;
2135 }
2136 }
2137
2138 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2139 if (rc)
2140 goto async_writev_out;
2141
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002142 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2143 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002144
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002145 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002146 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002147 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2148 if (wct == 14)
2149 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2150 smb->Reserved = 0xFFFFFFFF;
2151 smb->WriteMode = 0;
2152 smb->Remaining = 0;
2153
2154 smb->DataOffset =
2155 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2156
2157 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002158 iov[0].iov_len = 4;
2159 iov[0].iov_base = smb;
2160 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2161 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002162
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002163 rqst.rq_iov = iov;
2164 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002165 rqst.rq_pages = wdata->pages;
2166 rqst.rq_npages = wdata->nr_pages;
2167 rqst.rq_pagesz = wdata->pagesz;
2168 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169
Joe Perchesf96637b2013-05-04 22:12:25 -05002170 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2171 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002172
2173 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2174 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2175
2176 if (wct == 14) {
2177 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2178 put_bcc(wdata->bytes + 1, &smb->hdr);
2179 } else {
2180 /* wct == 12 */
2181 struct smb_com_writex_req *smbw =
2182 (struct smb_com_writex_req *)smb;
2183 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2184 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002185 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002186 }
2187
2188 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002189 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002190 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002191
2192 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002193 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002194 else
Steve French4a5c80d2014-02-07 20:45:12 -06002195 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002196
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002197async_writev_out:
2198 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002199 return rc;
2200}
2201
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002202int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002203CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002204 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205{
2206 int rc = -EACCES;
2207 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002208 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002209 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002210 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002211 __u32 pid = io_parms->pid;
2212 __u16 netfid = io_parms->netfid;
2213 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002214 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002215 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002216 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002218 *nbytes = 0;
2219
Joe Perchesf96637b2013-05-04 22:12:25 -05002220 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002221
Steve French4c3130e2008-12-09 00:28:16 +00002222 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002223 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002224 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002225 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002226 if ((offset >> 32) > 0) {
2227 /* can not handle big offset for old srv */
2228 return -EIO;
2229 }
2230 }
Steve French8cc64c62005-10-03 13:49:43 -07002231 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 if (rc)
2233 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002234
2235 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2236 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2237
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 /* tcon and ses pointer are checked in smb_init */
2239 if (tcon->ses->server == NULL)
2240 return -ECONNABORTED;
2241
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002242 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 pSMB->Fid = netfid;
2244 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002245 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002246 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 pSMB->Reserved = 0xFFFFFFFF;
2248 pSMB->WriteMode = 0;
2249 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002250
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002252 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Steve French3e844692005-10-03 13:37:24 -07002254 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2255 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002256 /* header + 1 byte pad */
2257 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002258 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002259 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002260 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002261 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002262 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002263 pSMB->ByteCount = cpu_to_le16(count + 1);
2264 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002265 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002266 (struct smb_com_writex_req *)pSMB;
2267 pSMBW->ByteCount = cpu_to_le16(count + 5);
2268 }
Steve French3e844692005-10-03 13:37:24 -07002269 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002270 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002271 iov[0].iov_len = smb_hdr_len + 4;
2272 else /* wct == 12 pad bigger by four bytes */
2273 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002274
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002275 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2276 &rsp_iov);
2277 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002278 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002280 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002281 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002282 /* presumably this can not happen, but best to be safe */
2283 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002284 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002285 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002286 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2287 *nbytes = (*nbytes) << 16;
2288 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302289
2290 /*
2291 * Mask off high 16 bits when bytes written as returned by the
2292 * server is greater than bytes requested by the client. OS/2
2293 * servers are known to set incorrect CountHigh values.
2294 */
2295 if (*nbytes > count)
2296 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002299 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
Steve French50c2f752007-07-13 00:33:32 +00002301 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 since file handle passed in no longer valid */
2303
2304 return rc;
2305}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002306
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002307int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2308 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002309 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2310{
2311 int rc = 0;
2312 LOCK_REQ *pSMB = NULL;
2313 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002314 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002315 int resp_buf_type;
2316 __u16 count;
2317
Joe Perchesf96637b2013-05-04 22:12:25 -05002318 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2319 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002320
2321 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2322 if (rc)
2323 return rc;
2324
2325 pSMB->Timeout = 0;
2326 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2327 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2328 pSMB->LockType = lock_type;
2329 pSMB->AndXCommand = 0xFF; /* none */
2330 pSMB->Fid = netfid; /* netfid stays le */
2331
2332 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2333 inc_rfc1001_len(pSMB, count);
2334 pSMB->ByteCount = cpu_to_le16(count);
2335
2336 iov[0].iov_base = (char *)pSMB;
2337 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2338 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2339 iov[1].iov_base = (char *)buf;
2340 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2341
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002342 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002343 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2344 &rsp_iov);
2345 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002346 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002347 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002348
2349 return rc;
2350}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002351
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002353CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002354 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002356 const __u32 numLock, const __u8 lockType,
2357 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358{
2359 int rc = 0;
2360 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002361/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002363 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 __u16 count;
2365
Joe Perchesf96637b2013-05-04 22:12:25 -05002366 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2367 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002368 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2369
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 if (rc)
2371 return rc;
2372
Steve French790fe572007-07-07 19:25:05 +00002373 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002374 /* no response expected */
2375 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002377 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002378 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2380 } else {
2381 pSMB->Timeout = 0;
2382 }
2383
2384 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2385 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2386 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002387 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 pSMB->AndXCommand = 0xFF; /* none */
2389 pSMB->Fid = smb_file_id; /* netfid stays le */
2390
Steve French790fe572007-07-07 19:25:05 +00002391 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002392 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 /* BB where to store pid high? */
2394 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2395 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2396 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2397 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2398 count = sizeof(LOCKING_ANDX_RANGE);
2399 } else {
2400 /* oplock break */
2401 count = 0;
2402 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002403 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 pSMB->ByteCount = cpu_to_le16(count);
2405
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002406 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002407 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002408 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002409 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002410 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002411 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002412 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002413 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002414 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
Steve French50c2f752007-07-13 00:33:32 +00002416 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 since file handle passed in no longer valid */
2418 return rc;
2419}
2420
2421int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002422CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002423 const __u16 smb_file_id, const __u32 netpid,
2424 const loff_t start_offset, const __u64 len,
2425 struct file_lock *pLockData, const __u16 lock_type,
2426 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002427{
2428 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2429 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002430 struct cifs_posix_lock *parm_data;
2431 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002432 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002433 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002434 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002435 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002436 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002437 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002438
Joe Perchesf96637b2013-05-04 22:12:25 -05002439 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002440
Steve French08547b02006-02-28 22:39:25 +00002441 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2442
2443 if (rc)
2444 return rc;
2445
2446 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2447
Steve French50c2f752007-07-13 00:33:32 +00002448 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002449 pSMB->MaxSetupCount = 0;
2450 pSMB->Reserved = 0;
2451 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002452 pSMB->Reserved2 = 0;
2453 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2454 offset = param_offset + params;
2455
Steve French08547b02006-02-28 22:39:25 +00002456 count = sizeof(struct cifs_posix_lock);
2457 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002458 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002459 pSMB->SetupCount = 1;
2460 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002461 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002462 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2463 else
2464 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2465 byte_count = 3 /* pad */ + params + count;
2466 pSMB->DataCount = cpu_to_le16(count);
2467 pSMB->ParameterCount = cpu_to_le16(params);
2468 pSMB->TotalDataCount = pSMB->DataCount;
2469 pSMB->TotalParameterCount = pSMB->ParameterCount;
2470 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002471 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002472 (((char *) &pSMB->hdr.Protocol) + offset);
2473
2474 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002475 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002476 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002477 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002478 pSMB->Timeout = cpu_to_le32(-1);
2479 } else
2480 pSMB->Timeout = 0;
2481
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002482 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002483 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002484 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002485
2486 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002487 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002488 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2489 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002490 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002491 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002492 if (waitFlag) {
2493 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2494 (struct smb_hdr *) pSMBr, &bytes_returned);
2495 } else {
Steve French133672e2007-11-13 22:41:37 +00002496 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002497 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002498 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002499 &resp_buf_type, timeout, &rsp_iov);
2500 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002501 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002502 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002503
Steve French08547b02006-02-28 22:39:25 +00002504 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002505 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002506 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002507 /* lock structure can be returned on get */
2508 __u16 data_offset;
2509 __u16 data_count;
2510 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002511
Jeff Layton820a8032011-05-04 08:05:26 -04002512 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002513 rc = -EIO; /* bad smb */
2514 goto plk_err_exit;
2515 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002516 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2517 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002518 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002519 rc = -EIO;
2520 goto plk_err_exit;
2521 }
2522 parm_data = (struct cifs_posix_lock *)
2523 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002524 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002525 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002526 else {
2527 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002528 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002529 pLockData->fl_type = F_RDLCK;
2530 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002531 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002532 pLockData->fl_type = F_WRLCK;
2533
Steve French5443d132011-03-13 05:08:25 +00002534 pLockData->fl_start = le64_to_cpu(parm_data->start);
2535 pLockData->fl_end = pLockData->fl_start +
2536 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002537 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002538 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002539 }
Steve French50c2f752007-07-13 00:33:32 +00002540
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002541plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002542 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002543
Steve French08547b02006-02-28 22:39:25 +00002544 /* Note: On -EAGAIN error only caller can retry on handle based calls
2545 since file handle passed in no longer valid */
2546
2547 return rc;
2548}
2549
2550
2551int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002552CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553{
2554 int rc = 0;
2555 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002556 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
2558/* do not retry on dead session on close */
2559 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002560 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 return 0;
2562 if (rc)
2563 return rc;
2564
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002566 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002568 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002569 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002570 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002572 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002574 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 }
2576 }
2577
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002579 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 rc = 0;
2581
2582 return rc;
2583}
2584
2585int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002586CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002587{
2588 int rc = 0;
2589 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002590 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002591
2592 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2593 if (rc)
2594 return rc;
2595
2596 pSMB->FileID = (__u16) smb_file_id;
2597 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002598 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002599 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002600 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002601 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002602 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002603
2604 return rc;
2605}
2606
2607int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002608CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002609 const char *from_name, const char *to_name,
2610 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611{
2612 int rc = 0;
2613 RENAME_REQ *pSMB = NULL;
2614 RENAME_RSP *pSMBr = NULL;
2615 int bytes_returned;
2616 int name_len, name_len2;
2617 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002618 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
Joe Perchesf96637b2013-05-04 22:12:25 -05002620 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621renameRetry:
2622 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2623 (void **) &pSMBr);
2624 if (rc)
2625 return rc;
2626
2627 pSMB->BufferFormat = 0x04;
2628 pSMB->SearchAttributes =
2629 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2630 ATTR_DIRECTORY);
2631
2632 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002633 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2634 from_name, PATH_MAX,
2635 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 name_len++; /* trailing null */
2637 name_len *= 2;
2638 pSMB->OldFileName[name_len] = 0x04; /* pad */
2639 /* protocol requires ASCII signature byte on Unicode string */
2640 pSMB->OldFileName[name_len + 1] = 0x00;
2641 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002642 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002643 to_name, PATH_MAX, cifs_sb->local_nls,
2644 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2646 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002647 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002648 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002650 strncpy(pSMB->OldFileName, from_name, name_len);
2651 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 name_len2++; /* trailing null */
2653 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002654 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 name_len2++; /* trailing null */
2656 name_len2++; /* signature byte */
2657 }
2658
2659 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002660 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 pSMB->ByteCount = cpu_to_le16(count);
2662
2663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002665 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002666 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002667 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 cifs_buf_release(pSMB);
2670
2671 if (rc == -EAGAIN)
2672 goto renameRetry;
2673
2674 return rc;
2675}
2676
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002677int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002678 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002679 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680{
2681 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2682 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002683 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 char *data_offset;
2685 char dummy_string[30];
2686 int rc = 0;
2687 int bytes_returned = 0;
2688 int len_of_str;
2689 __u16 params, param_offset, offset, count, byte_count;
2690
Joe Perchesf96637b2013-05-04 22:12:25 -05002691 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2693 (void **) &pSMBr);
2694 if (rc)
2695 return rc;
2696
2697 params = 6;
2698 pSMB->MaxSetupCount = 0;
2699 pSMB->Reserved = 0;
2700 pSMB->Flags = 0;
2701 pSMB->Timeout = 0;
2702 pSMB->Reserved2 = 0;
2703 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2704 offset = param_offset + params;
2705
2706 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2707 rename_info = (struct set_file_rename *) data_offset;
2708 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002709 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 pSMB->SetupCount = 1;
2711 pSMB->Reserved3 = 0;
2712 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2713 byte_count = 3 /* pad */ + params;
2714 pSMB->ParameterCount = cpu_to_le16(params);
2715 pSMB->TotalParameterCount = pSMB->ParameterCount;
2716 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2717 pSMB->DataOffset = cpu_to_le16(offset);
2718 /* construct random name ".cifs_tmp<inodenum><mid>" */
2719 rename_info->overwrite = cpu_to_le32(1);
2720 rename_info->root_fid = 0;
2721 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002722 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002723 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002724 len_of_str =
2725 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002726 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002728 len_of_str =
2729 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002730 target_name, PATH_MAX, nls_codepage,
2731 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 }
2733 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002734 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 byte_count += count;
2736 pSMB->DataCount = cpu_to_le16(count);
2737 pSMB->TotalDataCount = pSMB->DataCount;
2738 pSMB->Fid = netfid;
2739 pSMB->InformationLevel =
2740 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2741 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002742 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 pSMB->ByteCount = cpu_to_le16(byte_count);
2744 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002746 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002747 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002748 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2749 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002750
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 cifs_buf_release(pSMB);
2752
2753 /* Note: On -EAGAIN error only caller can retry on handle based calls
2754 since file handle passed in no longer valid */
2755
2756 return rc;
2757}
2758
2759int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002760CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2761 const char *fromName, const __u16 target_tid, const char *toName,
2762 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763{
2764 int rc = 0;
2765 COPY_REQ *pSMB = NULL;
2766 COPY_RSP *pSMBr = NULL;
2767 int bytes_returned;
2768 int name_len, name_len2;
2769 __u16 count;
2770
Joe Perchesf96637b2013-05-04 22:12:25 -05002771 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772copyRetry:
2773 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2774 (void **) &pSMBr);
2775 if (rc)
2776 return rc;
2777
2778 pSMB->BufferFormat = 0x04;
2779 pSMB->Tid2 = target_tid;
2780
2781 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2782
2783 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002784 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2785 fromName, PATH_MAX, nls_codepage,
2786 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 name_len++; /* trailing null */
2788 name_len *= 2;
2789 pSMB->OldFileName[name_len] = 0x04; /* pad */
2790 /* protocol requires ASCII signature byte on Unicode string */
2791 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002792 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002793 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2794 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2796 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002797 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 name_len = strnlen(fromName, PATH_MAX);
2799 name_len++; /* trailing null */
2800 strncpy(pSMB->OldFileName, fromName, name_len);
2801 name_len2 = strnlen(toName, PATH_MAX);
2802 name_len2++; /* trailing null */
2803 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2804 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2805 name_len2++; /* trailing null */
2806 name_len2++; /* signature byte */
2807 }
2808
2809 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002810 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 pSMB->ByteCount = cpu_to_le16(count);
2812
2813 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2814 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2815 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002816 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2817 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 }
Steve French0d817bc2008-05-22 02:02:03 +00002819 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
2821 if (rc == -EAGAIN)
2822 goto copyRetry;
2823
2824 return rc;
2825}
2826
2827int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002828CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831{
2832 TRANSACTION2_SPI_REQ *pSMB = NULL;
2833 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2834 char *data_offset;
2835 int name_len;
2836 int name_len_target;
2837 int rc = 0;
2838 int bytes_returned = 0;
2839 __u16 params, param_offset, offset, byte_count;
2840
Joe Perchesf96637b2013-05-04 22:12:25 -05002841 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842createSymLinkRetry:
2843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2844 (void **) &pSMBr);
2845 if (rc)
2846 return rc;
2847
2848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2849 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002850 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2851 /* find define for this maxpathcomponent */
2852 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len++; /* trailing null */
2854 name_len *= 2;
2855
Steve French50c2f752007-07-13 00:33:32 +00002856 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 name_len = strnlen(fromName, PATH_MAX);
2858 name_len++; /* trailing null */
2859 strncpy(pSMB->FileName, fromName, name_len);
2860 }
2861 params = 6 + name_len;
2862 pSMB->MaxSetupCount = 0;
2863 pSMB->Reserved = 0;
2864 pSMB->Flags = 0;
2865 pSMB->Timeout = 0;
2866 pSMB->Reserved2 = 0;
2867 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002868 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 offset = param_offset + params;
2870
2871 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2872 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2873 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002874 cifsConvertToUTF16((__le16 *) data_offset, toName,
2875 /* find define for this maxpathcomponent */
2876 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 name_len_target++; /* trailing null */
2878 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002879 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 name_len_target = strnlen(toName, PATH_MAX);
2881 name_len_target++; /* trailing null */
2882 strncpy(data_offset, toName, name_len_target);
2883 }
2884
2885 pSMB->MaxParameterCount = cpu_to_le16(2);
2886 /* BB find exact max on data count below from sess */
2887 pSMB->MaxDataCount = cpu_to_le16(1000);
2888 pSMB->SetupCount = 1;
2889 pSMB->Reserved3 = 0;
2890 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2891 byte_count = 3 /* pad */ + params + name_len_target;
2892 pSMB->DataCount = cpu_to_le16(name_len_target);
2893 pSMB->ParameterCount = cpu_to_le16(params);
2894 pSMB->TotalDataCount = pSMB->DataCount;
2895 pSMB->TotalParameterCount = pSMB->ParameterCount;
2896 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2897 pSMB->DataOffset = cpu_to_le16(offset);
2898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2899 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002900 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 pSMB->ByteCount = cpu_to_le16(byte_count);
2902 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2903 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002904 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002905 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002906 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2907 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
Steve French0d817bc2008-05-22 02:02:03 +00002909 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
2911 if (rc == -EAGAIN)
2912 goto createSymLinkRetry;
2913
2914 return rc;
2915}
2916
2917int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002918CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002920 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921{
2922 TRANSACTION2_SPI_REQ *pSMB = NULL;
2923 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2924 char *data_offset;
2925 int name_len;
2926 int name_len_target;
2927 int rc = 0;
2928 int bytes_returned = 0;
2929 __u16 params, param_offset, offset, byte_count;
2930
Joe Perchesf96637b2013-05-04 22:12:25 -05002931 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932createHardLinkRetry:
2933 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2934 (void **) &pSMBr);
2935 if (rc)
2936 return rc;
2937
2938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002939 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2940 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 name_len++; /* trailing null */
2942 name_len *= 2;
2943
Steve French50c2f752007-07-13 00:33:32 +00002944 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 name_len = strnlen(toName, PATH_MAX);
2946 name_len++; /* trailing null */
2947 strncpy(pSMB->FileName, toName, name_len);
2948 }
2949 params = 6 + name_len;
2950 pSMB->MaxSetupCount = 0;
2951 pSMB->Reserved = 0;
2952 pSMB->Flags = 0;
2953 pSMB->Timeout = 0;
2954 pSMB->Reserved2 = 0;
2955 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002956 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 offset = param_offset + params;
2958
2959 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2961 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002962 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len_target++; /* trailing null */
2965 name_len_target *= 2;
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_target = strnlen(fromName, PATH_MAX);
2968 name_len_target++; /* trailing null */
2969 strncpy(data_offset, fromName, name_len_target);
2970 }
2971
2972 pSMB->MaxParameterCount = cpu_to_le16(2);
2973 /* BB find exact max on data count below from sess*/
2974 pSMB->MaxDataCount = cpu_to_le16(1000);
2975 pSMB->SetupCount = 1;
2976 pSMB->Reserved3 = 0;
2977 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2978 byte_count = 3 /* pad */ + params + name_len_target;
2979 pSMB->ParameterCount = cpu_to_le16(params);
2980 pSMB->TotalParameterCount = pSMB->ParameterCount;
2981 pSMB->DataCount = cpu_to_le16(name_len_target);
2982 pSMB->TotalDataCount = pSMB->DataCount;
2983 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2984 pSMB->DataOffset = cpu_to_le16(offset);
2985 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2986 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002987 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 pSMB->ByteCount = cpu_to_le16(byte_count);
2989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002991 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002992 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002993 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2994 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 cifs_buf_release(pSMB);
2997 if (rc == -EAGAIN)
2998 goto createHardLinkRetry;
2999
3000 return rc;
3001}
3002
3003int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003004CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003005 const char *from_name, const char *to_name,
3006 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007{
3008 int rc = 0;
3009 NT_RENAME_REQ *pSMB = NULL;
3010 RENAME_RSP *pSMBr = NULL;
3011 int bytes_returned;
3012 int name_len, name_len2;
3013 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003014 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015
Joe Perchesf96637b2013-05-04 22:12:25 -05003016 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017winCreateHardLinkRetry:
3018
3019 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3020 (void **) &pSMBr);
3021 if (rc)
3022 return rc;
3023
3024 pSMB->SearchAttributes =
3025 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3026 ATTR_DIRECTORY);
3027 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3028 pSMB->ClusterCount = 0;
3029
3030 pSMB->BufferFormat = 0x04;
3031
3032 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3033 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003034 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3035 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 name_len++; /* trailing null */
3037 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003038
3039 /* protocol specifies ASCII buffer format (0x04) for unicode */
3040 pSMB->OldFileName[name_len] = 0x04;
3041 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003043 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003044 to_name, PATH_MAX, cifs_sb->local_nls,
3045 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3047 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003048 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003049 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003051 strncpy(pSMB->OldFileName, from_name, name_len);
3052 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 name_len2++; /* trailing null */
3054 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003055 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 name_len2++; /* trailing null */
3057 name_len2++; /* signature byte */
3058 }
3059
3060 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003061 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 pSMB->ByteCount = cpu_to_le16(count);
3063
3064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003066 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003067 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003068 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003069
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 cifs_buf_release(pSMB);
3071 if (rc == -EAGAIN)
3072 goto winCreateHardLinkRetry;
3073
3074 return rc;
3075}
3076
3077int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003078CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003079 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003080 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081{
3082/* SMB_QUERY_FILE_UNIX_LINK */
3083 TRANSACTION2_QPI_REQ *pSMB = NULL;
3084 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3085 int rc = 0;
3086 int bytes_returned;
3087 int name_len;
3088 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003089 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090
Joe Perchesf96637b2013-05-04 22:12:25 -05003091 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
3093querySymLinkRetry:
3094 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3095 (void **) &pSMBr);
3096 if (rc)
3097 return rc;
3098
3099 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3100 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003101 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3102 searchName, PATH_MAX, nls_codepage,
3103 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 name_len++; /* trailing null */
3105 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003106 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 name_len = strnlen(searchName, PATH_MAX);
3108 name_len++; /* trailing null */
3109 strncpy(pSMB->FileName, searchName, name_len);
3110 }
3111
3112 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3113 pSMB->TotalDataCount = 0;
3114 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003115 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 pSMB->MaxSetupCount = 0;
3117 pSMB->Reserved = 0;
3118 pSMB->Flags = 0;
3119 pSMB->Timeout = 0;
3120 pSMB->Reserved2 = 0;
3121 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003122 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 pSMB->DataCount = 0;
3124 pSMB->DataOffset = 0;
3125 pSMB->SetupCount = 1;
3126 pSMB->Reserved3 = 0;
3127 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3128 byte_count = params + 1 /* pad */ ;
3129 pSMB->TotalParameterCount = cpu_to_le16(params);
3130 pSMB->ParameterCount = pSMB->TotalParameterCount;
3131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3132 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003133 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 pSMB->ByteCount = cpu_to_le16(byte_count);
3135
3136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3138 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003139 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 } else {
3141 /* decode response */
3142
3143 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003145 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003146 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003148 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003149 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150
Jeff Layton460b9692009-04-30 07:17:56 -04003151 data_start = ((char *) &pSMBr->hdr.Protocol) +
3152 le16_to_cpu(pSMBr->t2.DataOffset);
3153
Steve French0e0d2cf2009-05-01 05:27:32 +00003154 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3155 is_unicode = true;
3156 else
3157 is_unicode = false;
3158
Steve French737b7582005-04-28 22:41:06 -07003159 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003160 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3161 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003162 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003163 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 }
3165 }
3166 cifs_buf_release(pSMB);
3167 if (rc == -EAGAIN)
3168 goto querySymLinkRetry;
3169 return rc;
3170}
3171
Steve Frenchc52a9552011-02-24 06:16:22 +00003172/*
3173 * Recent Windows versions now create symlinks more frequently
3174 * and they use the "reparse point" mechanism below. We can of course
3175 * do symlinks nicely to Samba and other servers which support the
3176 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3177 * "MF" symlinks optionally, but for recent Windows we really need to
3178 * reenable the code below and fix the cifs_symlink callers to handle this.
3179 * In the interim this code has been moved to its own config option so
3180 * it is not compiled in by default until callers fixed up and more tested.
3181 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003183CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3184 __u16 fid, char **symlinkinfo,
3185 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186{
3187 int rc = 0;
3188 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003189 struct smb_com_transaction_ioctl_req *pSMB;
3190 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003191 bool is_unicode;
3192 unsigned int sub_len;
3193 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003194 struct reparse_symlink_data *reparse_buf;
3195 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003196 __u32 data_offset, data_count;
3197 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003199 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3201 (void **) &pSMBr);
3202 if (rc)
3203 return rc;
3204
3205 pSMB->TotalParameterCount = 0 ;
3206 pSMB->TotalDataCount = 0;
3207 pSMB->MaxParameterCount = cpu_to_le32(2);
3208 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003209 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 pSMB->MaxSetupCount = 4;
3211 pSMB->Reserved = 0;
3212 pSMB->ParameterOffset = 0;
3213 pSMB->DataCount = 0;
3214 pSMB->DataOffset = 0;
3215 pSMB->SetupCount = 4;
3216 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3217 pSMB->ParameterCount = pSMB->TotalParameterCount;
3218 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3219 pSMB->IsFsctl = 1; /* FSCTL */
3220 pSMB->IsRootFlag = 0;
3221 pSMB->Fid = fid; /* file handle always le */
3222 pSMB->ByteCount = 0;
3223
3224 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3225 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3226 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003227 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003228 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 }
Steve French989c7e52009-05-02 05:32:20 +00003230
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003231 data_offset = le32_to_cpu(pSMBr->DataOffset);
3232 data_count = le32_to_cpu(pSMBr->DataCount);
3233 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3234 /* BB also check enough total bytes returned */
3235 rc = -EIO; /* bad smb */
3236 goto qreparse_out;
3237 }
3238 if (!data_count || (data_count > 2048)) {
3239 rc = -EIO;
3240 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3241 goto qreparse_out;
3242 }
3243 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003244 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003245 ((char *)&pSMBr->hdr.Protocol + data_offset);
3246 if ((char *)reparse_buf >= end_of_smb) {
3247 rc = -EIO;
3248 goto qreparse_out;
3249 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003250 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3251 cifs_dbg(FYI, "NFS style reparse tag\n");
3252 posix_buf = (struct reparse_posix_data *)reparse_buf;
3253
3254 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3255 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3256 le64_to_cpu(posix_buf->InodeType));
3257 rc = -EOPNOTSUPP;
3258 goto qreparse_out;
3259 }
3260 is_unicode = true;
3261 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3262 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3263 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3264 rc = -EIO;
3265 goto qreparse_out;
3266 }
3267 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3268 sub_len, is_unicode, nls_codepage);
3269 goto qreparse_out;
3270 } else if (reparse_buf->ReparseTag !=
3271 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3272 rc = -EOPNOTSUPP;
3273 goto qreparse_out;
3274 }
3275
3276 /* Reparse tag is NTFS symlink */
3277 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3278 reparse_buf->PathBuffer;
3279 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3280 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003281 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3282 rc = -EIO;
3283 goto qreparse_out;
3284 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003285 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3286 is_unicode = true;
3287 else
3288 is_unicode = false;
3289
3290 /* BB FIXME investigate remapping reserved chars here */
3291 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3292 nls_codepage);
3293 if (!*symlinkinfo)
3294 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003296 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003298 /*
3299 * Note: On -EAGAIN error only caller can retry on handle based calls
3300 * since file handle passed in no longer valid.
3301 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 return rc;
3303}
3304
Steve Frenchc7f508a2013-10-14 15:27:32 -05003305int
3306CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3307 __u16 fid)
3308{
3309 int rc = 0;
3310 int bytes_returned;
3311 struct smb_com_transaction_compr_ioctl_req *pSMB;
3312 struct smb_com_transaction_ioctl_rsp *pSMBr;
3313
3314 cifs_dbg(FYI, "Set compression for %u\n", fid);
3315 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3316 (void **) &pSMBr);
3317 if (rc)
3318 return rc;
3319
3320 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3321
3322 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003323 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003324 pSMB->MaxParameterCount = 0;
3325 pSMB->MaxDataCount = 0;
3326 pSMB->MaxSetupCount = 4;
3327 pSMB->Reserved = 0;
3328 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003329 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003330 pSMB->DataOffset =
3331 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3332 compression_state) - 4); /* 84 */
3333 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003334 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003335 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003336 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003337 pSMB->IsFsctl = 1; /* FSCTL */
3338 pSMB->IsRootFlag = 0;
3339 pSMB->Fid = fid; /* file handle always le */
3340 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003341 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003342 inc_rfc1001_len(pSMB, 5);
3343
3344 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3345 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3346 if (rc)
3347 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3348
3349 cifs_buf_release(pSMB);
3350
3351 /*
3352 * Note: On -EAGAIN error only caller can retry on handle based calls
3353 * since file handle passed in no longer valid.
3354 */
3355 return rc;
3356}
3357
3358
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359#ifdef CONFIG_CIFS_POSIX
3360
3361/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003362static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003363 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364{
3365 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003366 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3367 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3368 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003369/*
3370 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3371 ace->e_perm, ace->e_tag, ace->e_id);
3372*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373
3374 return;
3375}
3376
3377/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003378static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3379 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380{
3381 int size = 0;
3382 int i;
3383 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003384 struct cifs_posix_ace *pACE;
3385 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003386 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
3388 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3389 return -EOPNOTSUPP;
3390
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003391 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 count = le16_to_cpu(cifs_acl->access_entry_count);
3393 pACE = &cifs_acl->ace_array[0];
3394 size = sizeof(struct cifs_posix_acl);
3395 size += sizeof(struct cifs_posix_ace) * count;
3396 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003397 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003398 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3399 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 return -EINVAL;
3401 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003402 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 count = le16_to_cpu(cifs_acl->access_entry_count);
3404 size = sizeof(struct cifs_posix_acl);
3405 size += sizeof(struct cifs_posix_ace) * count;
3406/* skip past access ACEs to get to default ACEs */
3407 pACE = &cifs_acl->ace_array[count];
3408 count = le16_to_cpu(cifs_acl->default_entry_count);
3409 size += sizeof(struct cifs_posix_ace) * count;
3410 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003411 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 return -EINVAL;
3413 } else {
3414 /* illegal type */
3415 return -EINVAL;
3416 }
3417
3418 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003419 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003420 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003421 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 return -ERANGE;
3423 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003424 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3425
Steve Frenchff7feac2005-11-15 16:45:16 -08003426 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003427 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003428 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003429 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 }
3431 }
3432 return size;
3433}
3434
Steve French50c2f752007-07-13 00:33:32 +00003435static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003436 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437{
3438 __u16 rc = 0; /* 0 = ACL converted ok */
3439
Steve Frenchff7feac2005-11-15 16:45:16 -08003440 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3441 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003443 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 /* Probably no need to le convert -1 on any arch but can not hurt */
3445 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003446 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003447 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003448/*
3449 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3450 ace->e_perm, ace->e_tag, ace->e_id);
3451*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 return rc;
3453}
3454
3455/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003456static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3457 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
3459 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003460 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003461 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003462 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 int count;
3464 int i;
3465
Steve French790fe572007-07-07 19:25:05 +00003466 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 return 0;
3468
3469 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003470 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3471 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003472 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003473 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3474 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 return 0;
3476 }
3477 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003478 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003479 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003480 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003481 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003482 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003483 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003484 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003485 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 return 0;
3487 }
Steve French50c2f752007-07-13 00:33:32 +00003488 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003489 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003490 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 /* ACE not converted */
3492 break;
3493 }
3494 }
Steve French790fe572007-07-07 19:25:05 +00003495 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3497 rc += sizeof(struct cifs_posix_acl);
3498 /* BB add check to make sure ACL does not overflow SMB */
3499 }
3500 return rc;
3501}
3502
3503int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003504CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003505 const unsigned char *searchName,
3506 char *acl_inf, const int buflen, const int acl_type,
3507 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508{
3509/* SMB_QUERY_POSIX_ACL */
3510 TRANSACTION2_QPI_REQ *pSMB = NULL;
3511 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3512 int rc = 0;
3513 int bytes_returned;
3514 int name_len;
3515 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003516
Joe Perchesf96637b2013-05-04 22:12:25 -05003517 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519queryAclRetry:
3520 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3521 (void **) &pSMBr);
3522 if (rc)
3523 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003524
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3526 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003527 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3528 searchName, PATH_MAX, nls_codepage,
3529 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 name_len++; /* trailing null */
3531 name_len *= 2;
3532 pSMB->FileName[name_len] = 0;
3533 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003534 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 name_len = strnlen(searchName, PATH_MAX);
3536 name_len++; /* trailing null */
3537 strncpy(pSMB->FileName, searchName, name_len);
3538 }
3539
3540 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3541 pSMB->TotalDataCount = 0;
3542 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003543 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 pSMB->MaxDataCount = cpu_to_le16(4000);
3545 pSMB->MaxSetupCount = 0;
3546 pSMB->Reserved = 0;
3547 pSMB->Flags = 0;
3548 pSMB->Timeout = 0;
3549 pSMB->Reserved2 = 0;
3550 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003551 offsetof(struct smb_com_transaction2_qpi_req,
3552 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 pSMB->DataCount = 0;
3554 pSMB->DataOffset = 0;
3555 pSMB->SetupCount = 1;
3556 pSMB->Reserved3 = 0;
3557 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3558 byte_count = params + 1 /* pad */ ;
3559 pSMB->TotalParameterCount = cpu_to_le16(params);
3560 pSMB->ParameterCount = pSMB->TotalParameterCount;
3561 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3562 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003563 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 pSMB->ByteCount = cpu_to_le16(byte_count);
3565
3566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003568 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003570 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 } else {
3572 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003573
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003576 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 rc = -EIO; /* bad smb */
3578 else {
3579 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3580 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3581 rc = cifs_copy_posix_acl(acl_inf,
3582 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003583 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 }
3585 }
3586 cifs_buf_release(pSMB);
3587 if (rc == -EAGAIN)
3588 goto queryAclRetry;
3589 return rc;
3590}
3591
3592int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003593CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003594 const unsigned char *fileName,
3595 const char *local_acl, const int buflen,
3596 const int acl_type,
3597 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598{
3599 struct smb_com_transaction2_spi_req *pSMB = NULL;
3600 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3601 char *parm_data;
3602 int name_len;
3603 int rc = 0;
3604 int bytes_returned = 0;
3605 __u16 params, byte_count, data_count, param_offset, offset;
3606
Joe Perchesf96637b2013-05-04 22:12:25 -05003607 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608setAclRetry:
3609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003610 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 if (rc)
3612 return rc;
3613 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3614 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003615 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3616 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 name_len++; /* trailing null */
3618 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003619 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 name_len = strnlen(fileName, PATH_MAX);
3621 name_len++; /* trailing null */
3622 strncpy(pSMB->FileName, fileName, name_len);
3623 }
3624 params = 6 + name_len;
3625 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003626 /* BB find max SMB size from sess */
3627 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 pSMB->MaxSetupCount = 0;
3629 pSMB->Reserved = 0;
3630 pSMB->Flags = 0;
3631 pSMB->Timeout = 0;
3632 pSMB->Reserved2 = 0;
3633 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003634 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 offset = param_offset + params;
3636 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3637 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3638
3639 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003640 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
Steve French790fe572007-07-07 19:25:05 +00003642 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 rc = -EOPNOTSUPP;
3644 goto setACLerrorExit;
3645 }
3646 pSMB->DataOffset = cpu_to_le16(offset);
3647 pSMB->SetupCount = 1;
3648 pSMB->Reserved3 = 0;
3649 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3650 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3651 byte_count = 3 /* pad */ + params + data_count;
3652 pSMB->DataCount = cpu_to_le16(data_count);
3653 pSMB->TotalDataCount = pSMB->DataCount;
3654 pSMB->ParameterCount = cpu_to_le16(params);
3655 pSMB->TotalParameterCount = pSMB->ParameterCount;
3656 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003657 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 pSMB->ByteCount = cpu_to_le16(byte_count);
3659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003661 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003662 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663
3664setACLerrorExit:
3665 cifs_buf_release(pSMB);
3666 if (rc == -EAGAIN)
3667 goto setAclRetry;
3668 return rc;
3669}
3670
Steve Frenchf654bac2005-04-28 22:41:04 -07003671/* BB fix tabs in this function FIXME BB */
3672int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003673CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003674 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003675{
Steve French50c2f752007-07-13 00:33:32 +00003676 int rc = 0;
3677 struct smb_t2_qfi_req *pSMB = NULL;
3678 struct smb_t2_qfi_rsp *pSMBr = NULL;
3679 int bytes_returned;
3680 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003681
Joe Perchesf96637b2013-05-04 22:12:25 -05003682 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003683 if (tcon == NULL)
3684 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003685
3686GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003687 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3688 (void **) &pSMBr);
3689 if (rc)
3690 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003691
Steve Frenchad7a2922008-02-07 23:25:02 +00003692 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003693 pSMB->t2.TotalDataCount = 0;
3694 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3695 /* BB find exact max data count below from sess structure BB */
3696 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3697 pSMB->t2.MaxSetupCount = 0;
3698 pSMB->t2.Reserved = 0;
3699 pSMB->t2.Flags = 0;
3700 pSMB->t2.Timeout = 0;
3701 pSMB->t2.Reserved2 = 0;
3702 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3703 Fid) - 4);
3704 pSMB->t2.DataCount = 0;
3705 pSMB->t2.DataOffset = 0;
3706 pSMB->t2.SetupCount = 1;
3707 pSMB->t2.Reserved3 = 0;
3708 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3709 byte_count = params + 1 /* pad */ ;
3710 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3711 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3712 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3713 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003714 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003715 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003716 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003717
Steve French790fe572007-07-07 19:25:05 +00003718 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3719 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3720 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003721 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003722 } else {
3723 /* decode response */
3724 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003725 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003726 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003727 /* If rc should we check for EOPNOSUPP and
3728 disable the srvino flag? or in caller? */
3729 rc = -EIO; /* bad smb */
3730 else {
3731 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3732 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3733 struct file_chattr_info *pfinfo;
3734 /* BB Do we need a cast or hash here ? */
3735 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003736 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003737 rc = -EIO;
3738 goto GetExtAttrOut;
3739 }
3740 pfinfo = (struct file_chattr_info *)
3741 (data_offset + (char *) &pSMBr->hdr.Protocol);
3742 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003743 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003744 }
3745 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003746GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003747 cifs_buf_release(pSMB);
3748 if (rc == -EAGAIN)
3749 goto GetExtAttrRetry;
3750 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003751}
3752
Steve Frenchf654bac2005-04-28 22:41:04 -07003753#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754
Jeff Layton79df1ba2010-12-06 12:52:08 -05003755#ifdef CONFIG_CIFS_ACL
3756/*
3757 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3758 * all NT TRANSACTS that we init here have total parm and data under about 400
3759 * bytes (to fit in small cifs buffer size), which is the case so far, it
3760 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3761 * returned setup area) and MaxParameterCount (returned parms size) must be set
3762 * by caller
3763 */
3764static int
3765smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003766 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003767 void **ret_buf)
3768{
3769 int rc;
3770 __u32 temp_offset;
3771 struct smb_com_ntransact_req *pSMB;
3772
3773 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3774 (void **)&pSMB);
3775 if (rc)
3776 return rc;
3777 *ret_buf = (void *)pSMB;
3778 pSMB->Reserved = 0;
3779 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3780 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003781 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003782 pSMB->ParameterCount = pSMB->TotalParameterCount;
3783 pSMB->DataCount = pSMB->TotalDataCount;
3784 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3785 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3786 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3787 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3788 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3789 pSMB->SubCommand = cpu_to_le16(sub_command);
3790 return 0;
3791}
3792
3793static int
3794validate_ntransact(char *buf, char **ppparm, char **ppdata,
3795 __u32 *pparmlen, __u32 *pdatalen)
3796{
3797 char *end_of_smb;
3798 __u32 data_count, data_offset, parm_count, parm_offset;
3799 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003800 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003801
3802 *pdatalen = 0;
3803 *pparmlen = 0;
3804
3805 if (buf == NULL)
3806 return -EINVAL;
3807
3808 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3809
Jeff Layton820a8032011-05-04 08:05:26 -04003810 bcc = get_bcc(&pSMBr->hdr);
3811 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003812 (char *)&pSMBr->ByteCount;
3813
3814 data_offset = le32_to_cpu(pSMBr->DataOffset);
3815 data_count = le32_to_cpu(pSMBr->DataCount);
3816 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3817 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3818
3819 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3820 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3821
3822 /* should we also check that parm and data areas do not overlap? */
3823 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003824 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003825 return -EINVAL;
3826 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003827 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003828 return -EINVAL;
3829 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003830 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003831 return -EINVAL;
3832 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003833 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3834 *ppdata, data_count, (data_count + *ppdata),
3835 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003836 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003837 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003838 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003839 return -EINVAL;
3840 }
3841 *pdatalen = data_count;
3842 *pparmlen = parm_count;
3843 return 0;
3844}
3845
Steve French0a4b92c2006-01-12 15:44:21 -08003846/* Get Security Descriptor (by handle) from remote server for a file or dir */
3847int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003848CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003849 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003850{
3851 int rc = 0;
3852 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003853 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003854 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003855 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003856
Joe Perchesf96637b2013-05-04 22:12:25 -05003857 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003858
Steve French630f3f0c2007-10-25 21:17:17 +00003859 *pbuflen = 0;
3860 *acl_inf = NULL;
3861
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003862 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003863 8 /* parm len */, tcon, (void **) &pSMB);
3864 if (rc)
3865 return rc;
3866
3867 pSMB->MaxParameterCount = cpu_to_le32(4);
3868 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3869 pSMB->MaxSetupCount = 0;
3870 pSMB->Fid = fid; /* file handle always le */
3871 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3872 CIFS_ACL_DACL);
3873 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003874 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003875 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003876 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003877
Steve Frencha761ac52007-10-18 21:45:27 +00003878 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003879 0, &rsp_iov);
3880 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003881 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003882 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003883 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003884 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003885 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003886 __u32 parm_len;
3887 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003888 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003889 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003890
3891/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003892 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003893 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003894 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003895 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003896 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003897
Joe Perchesf96637b2013-05-04 22:12:25 -05003898 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3899 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003900
3901 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3902 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003903 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003904 goto qsec_out;
3905 }
3906
3907/* BB check that data area is minimum length and as big as acl_len */
3908
Steve Frenchaf6f4612007-10-16 18:40:37 +00003909 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003910 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003911 cifs_dbg(VFS, "acl length %d does not match %d\n",
3912 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003913 if (*pbuflen > acl_len)
3914 *pbuflen = acl_len;
3915 }
Steve French0a4b92c2006-01-12 15:44:21 -08003916
Steve French630f3f0c2007-10-25 21:17:17 +00003917 /* check if buffer is big enough for the acl
3918 header followed by the smallest SID */
3919 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3920 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003921 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003922 rc = -EINVAL;
3923 *pbuflen = 0;
3924 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003925 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003926 if (*acl_inf == NULL) {
3927 *pbuflen = 0;
3928 rc = -ENOMEM;
3929 }
Steve French630f3f0c2007-10-25 21:17:17 +00003930 }
Steve French0a4b92c2006-01-12 15:44:21 -08003931 }
3932qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003933 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003934 return rc;
3935}
Steve French97837582007-12-31 07:47:21 +00003936
3937int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003938CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003939 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003940{
3941 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3942 int rc = 0;
3943 int bytes_returned = 0;
3944 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003945 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003946
3947setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003948 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003949 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003950 return rc;
Steve French97837582007-12-31 07:47:21 +00003951
3952 pSMB->MaxSetupCount = 0;
3953 pSMB->Reserved = 0;
3954
3955 param_count = 8;
3956 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3957 data_count = acllen;
3958 data_offset = param_offset + param_count;
3959 byte_count = 3 /* pad */ + param_count;
3960
3961 pSMB->DataCount = cpu_to_le32(data_count);
3962 pSMB->TotalDataCount = pSMB->DataCount;
3963 pSMB->MaxParameterCount = cpu_to_le32(4);
3964 pSMB->MaxDataCount = cpu_to_le32(16384);
3965 pSMB->ParameterCount = cpu_to_le32(param_count);
3966 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3967 pSMB->TotalParameterCount = pSMB->ParameterCount;
3968 pSMB->DataOffset = cpu_to_le32(data_offset);
3969 pSMB->SetupCount = 0;
3970 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3971 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3972
3973 pSMB->Fid = fid; /* file handle always le */
3974 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003975 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003976
3977 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003978 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3979 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003980 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003981 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003982 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003983
3984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3986
Joe Perchesf96637b2013-05-04 22:12:25 -05003987 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3988 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003989 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003990 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003991 cifs_buf_release(pSMB);
3992
3993 if (rc == -EAGAIN)
3994 goto setCifsAclRetry;
3995
3996 return (rc);
3997}
3998
Jeff Layton79df1ba2010-12-06 12:52:08 -05003999#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004000
Steve French6b8edfe2005-08-23 20:26:03 -07004001/* Legacy Query Path Information call for lookup to old servers such
4002 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004003int
4004SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4005 const char *search_name, FILE_ALL_INFO *data,
4006 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004007{
Steve Frenchad7a2922008-02-07 23:25:02 +00004008 QUERY_INFORMATION_REQ *pSMB;
4009 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004010 int rc = 0;
4011 int bytes_returned;
4012 int name_len;
4013
Joe Perchesf96637b2013-05-04 22:12:25 -05004014 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004015QInfRetry:
4016 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004017 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004018 if (rc)
4019 return rc;
4020
4021 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4022 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004023 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004024 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004025 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004026 name_len++; /* trailing null */
4027 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004028 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004029 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004030 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004031 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004032 }
4033 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004034 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004035 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004036 pSMB->ByteCount = cpu_to_le16(name_len);
4037
4038 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004039 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004040 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004041 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004042 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004043 struct timespec ts;
4044 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004045
4046 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004047 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004048 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004049 ts.tv_nsec = 0;
4050 ts.tv_sec = time;
4051 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004052 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4053 data->LastWriteTime = data->ChangeTime;
4054 data->LastAccessTime = 0;
4055 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004056 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004057 data->EndOfFile = data->AllocationSize;
4058 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004059 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004060 } else
4061 rc = -EIO; /* bad buffer passed in */
4062
4063 cifs_buf_release(pSMB);
4064
4065 if (rc == -EAGAIN)
4066 goto QInfRetry;
4067
4068 return rc;
4069}
4070
Jeff Laytonbcd53572010-02-12 07:44:16 -05004071int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004072CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004073 u16 netfid, FILE_ALL_INFO *pFindData)
4074{
4075 struct smb_t2_qfi_req *pSMB = NULL;
4076 struct smb_t2_qfi_rsp *pSMBr = NULL;
4077 int rc = 0;
4078 int bytes_returned;
4079 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004080
Jeff Laytonbcd53572010-02-12 07:44:16 -05004081QFileInfoRetry:
4082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4083 (void **) &pSMBr);
4084 if (rc)
4085 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004086
Jeff Laytonbcd53572010-02-12 07:44:16 -05004087 params = 2 /* level */ + 2 /* fid */;
4088 pSMB->t2.TotalDataCount = 0;
4089 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4090 /* BB find exact max data count below from sess structure BB */
4091 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4092 pSMB->t2.MaxSetupCount = 0;
4093 pSMB->t2.Reserved = 0;
4094 pSMB->t2.Flags = 0;
4095 pSMB->t2.Timeout = 0;
4096 pSMB->t2.Reserved2 = 0;
4097 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4098 Fid) - 4);
4099 pSMB->t2.DataCount = 0;
4100 pSMB->t2.DataOffset = 0;
4101 pSMB->t2.SetupCount = 1;
4102 pSMB->t2.Reserved3 = 0;
4103 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4104 byte_count = params + 1 /* pad */ ;
4105 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4106 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4107 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4108 pSMB->Pad = 0;
4109 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004110 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004111 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004112
4113 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4114 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4115 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004116 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004117 } else { /* decode response */
4118 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4119
4120 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4121 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004122 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004123 rc = -EIO; /* bad smb */
4124 else if (pFindData) {
4125 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4126 memcpy((char *) pFindData,
4127 (char *) &pSMBr->hdr.Protocol +
4128 data_offset, sizeof(FILE_ALL_INFO));
4129 } else
4130 rc = -ENOMEM;
4131 }
4132 cifs_buf_release(pSMB);
4133 if (rc == -EAGAIN)
4134 goto QFileInfoRetry;
4135
4136 return rc;
4137}
Steve French6b8edfe2005-08-23 20:26:03 -07004138
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004140CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004141 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004142 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004143 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004145 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 TRANSACTION2_QPI_REQ *pSMB = NULL;
4147 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4148 int rc = 0;
4149 int bytes_returned;
4150 int name_len;
4151 __u16 params, byte_count;
4152
Joe Perchesf96637b2013-05-04 22:12:25 -05004153 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154QPathInfoRetry:
4155 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4156 (void **) &pSMBr);
4157 if (rc)
4158 return rc;
4159
4160 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4161 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004162 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004163 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 name_len++; /* trailing null */
4165 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004166 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004167 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004169 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 }
4171
Steve French50c2f752007-07-13 00:33:32 +00004172 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 pSMB->TotalDataCount = 0;
4174 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004175 /* BB find exact max SMB PDU from sess structure BB */
4176 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 pSMB->MaxSetupCount = 0;
4178 pSMB->Reserved = 0;
4179 pSMB->Flags = 0;
4180 pSMB->Timeout = 0;
4181 pSMB->Reserved2 = 0;
4182 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004183 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 pSMB->DataCount = 0;
4185 pSMB->DataOffset = 0;
4186 pSMB->SetupCount = 1;
4187 pSMB->Reserved3 = 0;
4188 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4189 byte_count = params + 1 /* pad */ ;
4190 pSMB->TotalParameterCount = cpu_to_le16(params);
4191 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004192 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004193 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4194 else
4195 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004197 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 pSMB->ByteCount = cpu_to_le16(byte_count);
4199
4200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4202 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004203 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 } else { /* decode response */
4205 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4206
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004207 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4208 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004209 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004211 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004212 rc = -EIO; /* 24 or 26 expected but we do not read
4213 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004214 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004215 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004217
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004218 /*
4219 * On legacy responses we do not read the last field,
4220 * EAsize, fortunately since it varies by subdialect and
4221 * also note it differs on Set vs Get, ie two bytes or 4
4222 * bytes depending but we don't care here.
4223 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004224 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004225 size = sizeof(FILE_INFO_STANDARD);
4226 else
4227 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004228 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004229 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 } else
4231 rc = -ENOMEM;
4232 }
4233 cifs_buf_release(pSMB);
4234 if (rc == -EAGAIN)
4235 goto QPathInfoRetry;
4236
4237 return rc;
4238}
4239
4240int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004241CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004242 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4243{
4244 struct smb_t2_qfi_req *pSMB = NULL;
4245 struct smb_t2_qfi_rsp *pSMBr = NULL;
4246 int rc = 0;
4247 int bytes_returned;
4248 __u16 params, byte_count;
4249
4250UnixQFileInfoRetry:
4251 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4252 (void **) &pSMBr);
4253 if (rc)
4254 return rc;
4255
4256 params = 2 /* level */ + 2 /* fid */;
4257 pSMB->t2.TotalDataCount = 0;
4258 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4259 /* BB find exact max data count below from sess structure BB */
4260 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4261 pSMB->t2.MaxSetupCount = 0;
4262 pSMB->t2.Reserved = 0;
4263 pSMB->t2.Flags = 0;
4264 pSMB->t2.Timeout = 0;
4265 pSMB->t2.Reserved2 = 0;
4266 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4267 Fid) - 4);
4268 pSMB->t2.DataCount = 0;
4269 pSMB->t2.DataOffset = 0;
4270 pSMB->t2.SetupCount = 1;
4271 pSMB->t2.Reserved3 = 0;
4272 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4273 byte_count = params + 1 /* pad */ ;
4274 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4275 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4276 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4277 pSMB->Pad = 0;
4278 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004279 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004280 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004281
4282 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4283 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4284 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004285 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004286 } else { /* decode response */
4287 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4288
Jeff Layton820a8032011-05-04 08:05:26 -04004289 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004290 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 -05004291 rc = -EIO; /* bad smb */
4292 } else {
4293 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4294 memcpy((char *) pFindData,
4295 (char *) &pSMBr->hdr.Protocol +
4296 data_offset,
4297 sizeof(FILE_UNIX_BASIC_INFO));
4298 }
4299 }
4300
4301 cifs_buf_release(pSMB);
4302 if (rc == -EAGAIN)
4303 goto UnixQFileInfoRetry;
4304
4305 return rc;
4306}
4307
4308int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004309CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004311 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004312 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313{
4314/* SMB_QUERY_FILE_UNIX_BASIC */
4315 TRANSACTION2_QPI_REQ *pSMB = NULL;
4316 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4317 int rc = 0;
4318 int bytes_returned = 0;
4319 int name_len;
4320 __u16 params, byte_count;
4321
Joe Perchesf96637b2013-05-04 22:12:25 -05004322 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323UnixQPathInfoRetry:
4324 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4325 (void **) &pSMBr);
4326 if (rc)
4327 return rc;
4328
4329 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4330 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004331 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4332 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 name_len++; /* trailing null */
4334 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004335 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 name_len = strnlen(searchName, PATH_MAX);
4337 name_len++; /* trailing null */
4338 strncpy(pSMB->FileName, searchName, name_len);
4339 }
4340
Steve French50c2f752007-07-13 00:33:32 +00004341 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 pSMB->TotalDataCount = 0;
4343 pSMB->MaxParameterCount = cpu_to_le16(2);
4344 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004345 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 pSMB->MaxSetupCount = 0;
4347 pSMB->Reserved = 0;
4348 pSMB->Flags = 0;
4349 pSMB->Timeout = 0;
4350 pSMB->Reserved2 = 0;
4351 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004352 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 pSMB->DataCount = 0;
4354 pSMB->DataOffset = 0;
4355 pSMB->SetupCount = 1;
4356 pSMB->Reserved3 = 0;
4357 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4358 byte_count = params + 1 /* pad */ ;
4359 pSMB->TotalParameterCount = cpu_to_le16(params);
4360 pSMB->ParameterCount = pSMB->TotalParameterCount;
4361 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4362 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004363 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 pSMB->ByteCount = cpu_to_le16(byte_count);
4365
4366 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4367 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4368 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004369 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 } else { /* decode response */
4371 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4372
Jeff Layton820a8032011-05-04 08:05:26 -04004373 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004374 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 -07004375 rc = -EIO; /* bad smb */
4376 } else {
4377 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4378 memcpy((char *) pFindData,
4379 (char *) &pSMBr->hdr.Protocol +
4380 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004381 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 }
4383 }
4384 cifs_buf_release(pSMB);
4385 if (rc == -EAGAIN)
4386 goto UnixQPathInfoRetry;
4387
4388 return rc;
4389}
4390
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391/* xid, tcon, searchName and codepage are input parms, rest are returned */
4392int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004393CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004394 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004395 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004396 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397{
4398/* level 257 SMB_ */
4399 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4400 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004401 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 int rc = 0;
4403 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004404 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004406 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
Joe Perchesf96637b2013-05-04 22:12:25 -05004408 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
4410findFirstRetry:
4411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4412 (void **) &pSMBr);
4413 if (rc)
4414 return rc;
4415
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004416 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004417 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004418
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4420 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004421 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4422 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004423 /* We can not add the asterik earlier in case
4424 it got remapped to 0xF03A as if it were part of the
4425 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004427 if (msearch) {
4428 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4429 pSMB->FileName[name_len+1] = 0;
4430 pSMB->FileName[name_len+2] = '*';
4431 pSMB->FileName[name_len+3] = 0;
4432 name_len += 4; /* now the trailing null */
4433 /* null terminate just in case */
4434 pSMB->FileName[name_len] = 0;
4435 pSMB->FileName[name_len+1] = 0;
4436 name_len += 2;
4437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 } else { /* BB add check for overrun of SMB buf BB */
4439 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004441 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 free buffer exit; BB */
4443 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004444 if (msearch) {
4445 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4446 pSMB->FileName[name_len+1] = '*';
4447 pSMB->FileName[name_len+2] = 0;
4448 name_len += 3;
4449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 }
4451
4452 params = 12 + name_len /* includes null */ ;
4453 pSMB->TotalDataCount = 0; /* no EAs */
4454 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004455 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 pSMB->MaxSetupCount = 0;
4457 pSMB->Reserved = 0;
4458 pSMB->Flags = 0;
4459 pSMB->Timeout = 0;
4460 pSMB->Reserved2 = 0;
4461 byte_count = params + 1 /* pad */ ;
4462 pSMB->TotalParameterCount = cpu_to_le16(params);
4463 pSMB->ParameterCount = pSMB->TotalParameterCount;
4464 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004465 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4466 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 pSMB->DataCount = 0;
4468 pSMB->DataOffset = 0;
4469 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4470 pSMB->Reserved3 = 0;
4471 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4472 pSMB->SearchAttributes =
4473 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4474 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004475 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004476 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4478
4479 /* BB what should we set StorageType to? Does it matter? BB */
4480 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004481 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 pSMB->ByteCount = cpu_to_le16(byte_count);
4483
4484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004486 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487
Steve French88274812006-03-09 22:21:45 +00004488 if (rc) {/* BB add logic to retry regular search if Unix search
4489 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004491 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004492
Steve French88274812006-03-09 22:21:45 +00004493 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
4495 /* BB eventually could optimize out free and realloc of buf */
4496 /* for this case */
4497 if (rc == -EAGAIN)
4498 goto findFirstRetry;
4499 } else { /* decode response */
4500 /* BB remember to free buffer if error BB */
4501 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004502 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004503 unsigned int lnoff;
4504
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004506 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 else
Steve French4b18f2a2008-04-29 00:06:05 +00004508 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
4510 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004511 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004512 psrch_inf->srch_entries_start =
4513 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4516 le16_to_cpu(pSMBr->t2.ParameterOffset));
4517
Steve French790fe572007-07-07 19:25:05 +00004518 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004519 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 else
Steve French4b18f2a2008-04-29 00:06:05 +00004521 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522
Steve French50c2f752007-07-13 00:33:32 +00004523 psrch_inf->entries_in_buffer =
4524 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004525 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004527 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004528 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004529 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004530 psrch_inf->last_entry = NULL;
4531 return rc;
4532 }
4533
Steve French0752f152008-10-07 20:03:33 +00004534 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004535 lnoff;
4536
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004537 if (pnetfid)
4538 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 } else {
4540 cifs_buf_release(pSMB);
4541 }
4542 }
4543
4544 return rc;
4545}
4546
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004547int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4548 __u16 searchHandle, __u16 search_flags,
4549 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550{
4551 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4552 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004553 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 char *response_data;
4555 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004556 int bytes_returned;
4557 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 __u16 params, byte_count;
4559
Joe Perchesf96637b2013-05-04 22:12:25 -05004560 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561
Steve French4b18f2a2008-04-29 00:06:05 +00004562 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 return -ENOENT;
4564
4565 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4566 (void **) &pSMBr);
4567 if (rc)
4568 return rc;
4569
Steve French50c2f752007-07-13 00:33:32 +00004570 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 byte_count = 0;
4572 pSMB->TotalDataCount = 0; /* no EAs */
4573 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004574 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 pSMB->MaxSetupCount = 0;
4576 pSMB->Reserved = 0;
4577 pSMB->Flags = 0;
4578 pSMB->Timeout = 0;
4579 pSMB->Reserved2 = 0;
4580 pSMB->ParameterOffset = cpu_to_le16(
4581 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4582 pSMB->DataCount = 0;
4583 pSMB->DataOffset = 0;
4584 pSMB->SetupCount = 1;
4585 pSMB->Reserved3 = 0;
4586 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4587 pSMB->SearchHandle = searchHandle; /* always kept as le */
4588 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004589 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4591 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004592 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593
4594 name_len = psrch_inf->resume_name_len;
4595 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004596 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4598 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004599 /* 14 byte parm len above enough for 2 byte null terminator */
4600 pSMB->ResumeFileName[name_len] = 0;
4601 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 } else {
4603 rc = -EINVAL;
4604 goto FNext2_err_exit;
4605 }
4606 byte_count = params + 1 /* pad */ ;
4607 pSMB->TotalParameterCount = cpu_to_le16(params);
4608 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004609 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004611
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004614 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 if (rc) {
4616 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004617 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004618 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004619 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004621 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 } else { /* decode response */
4623 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004624
Steve French790fe572007-07-07 19:25:05 +00004625 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004626 unsigned int lnoff;
4627
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 /* BB fixme add lock for file (srch_info) struct here */
4629 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004630 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 else
Steve French4b18f2a2008-04-29 00:06:05 +00004632 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 response_data = (char *) &pSMBr->hdr.Protocol +
4634 le16_to_cpu(pSMBr->t2.ParameterOffset);
4635 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4636 response_data = (char *)&pSMBr->hdr.Protocol +
4637 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004638 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004639 cifs_small_buf_release(
4640 psrch_inf->ntwrk_buf_start);
4641 else
4642 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 psrch_inf->srch_entries_start = response_data;
4644 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004645 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004646 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004647 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 else
Steve French4b18f2a2008-04-29 00:06:05 +00004649 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004650 psrch_inf->entries_in_buffer =
4651 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 psrch_inf->index_of_last_entry +=
4653 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004654 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004655 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004656 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004657 psrch_inf->last_entry = NULL;
4658 return rc;
4659 } else
4660 psrch_inf->last_entry =
4661 psrch_inf->srch_entries_start + lnoff;
4662
Joe Perchesf96637b2013-05-04 22:12:25 -05004663/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4664 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665
4666 /* BB fixme add unlock here */
4667 }
4668
4669 }
4670
4671 /* BB On error, should we leave previous search buf (and count and
4672 last entry fields) intact or free the previous one? */
4673
4674 /* Note: On -EAGAIN error only caller can retry on handle based calls
4675 since file handle passed in no longer valid */
4676FNext2_err_exit:
4677 if (rc != 0)
4678 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 return rc;
4680}
4681
4682int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004683CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004684 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685{
4686 int rc = 0;
4687 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688
Joe Perchesf96637b2013-05-04 22:12:25 -05004689 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4691
4692 /* no sense returning error if session restarted
4693 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004694 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 return 0;
4696 if (rc)
4697 return rc;
4698
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 pSMB->FileID = searchHandle;
4700 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004701 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004702 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004703 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004704 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004705
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004706 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707
4708 /* Since session is dead, search handle closed on server already */
4709 if (rc == -EAGAIN)
4710 rc = 0;
4711
4712 return rc;
4713}
4714
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004716CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004717 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004718 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719{
4720 int rc = 0;
4721 TRANSACTION2_QPI_REQ *pSMB = NULL;
4722 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4723 int name_len, bytes_returned;
4724 __u16 params, byte_count;
4725
Joe Perchesf96637b2013-05-04 22:12:25 -05004726 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004727 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004728 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729
4730GetInodeNumberRetry:
4731 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004732 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 if (rc)
4734 return rc;
4735
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4737 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004738 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004739 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004740 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 name_len++; /* trailing null */
4742 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004743 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004744 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004746 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 }
4748
4749 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4750 pSMB->TotalDataCount = 0;
4751 pSMB->MaxParameterCount = cpu_to_le16(2);
4752 /* BB find exact max data count below from sess structure BB */
4753 pSMB->MaxDataCount = cpu_to_le16(4000);
4754 pSMB->MaxSetupCount = 0;
4755 pSMB->Reserved = 0;
4756 pSMB->Flags = 0;
4757 pSMB->Timeout = 0;
4758 pSMB->Reserved2 = 0;
4759 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004760 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 pSMB->DataCount = 0;
4762 pSMB->DataOffset = 0;
4763 pSMB->SetupCount = 1;
4764 pSMB->Reserved3 = 0;
4765 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4766 byte_count = params + 1 /* pad */ ;
4767 pSMB->TotalParameterCount = cpu_to_le16(params);
4768 pSMB->ParameterCount = pSMB->TotalParameterCount;
4769 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4770 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004771 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 pSMB->ByteCount = cpu_to_le16(byte_count);
4773
4774 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4775 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4776 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004777 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 } else {
4779 /* decode response */
4780 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004782 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 /* If rc should we check for EOPNOSUPP and
4784 disable the srvino flag? or in caller? */
4785 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004786 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4788 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004789 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004791 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004792 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 rc = -EIO;
4794 goto GetInodeNumOut;
4795 }
4796 pfinfo = (struct file_internal_info *)
4797 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004798 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 }
4800 }
4801GetInodeNumOut:
4802 cifs_buf_release(pSMB);
4803 if (rc == -EAGAIN)
4804 goto GetInodeNumberRetry;
4805 return rc;
4806}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
4808int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004809CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004810 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004811 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004812 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813{
4814/* TRANS2_GET_DFS_REFERRAL */
4815 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4816 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 int rc = 0;
4818 int bytes_returned;
4819 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004821 *num_of_nodes = 0;
4822 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823
Joe Perchesf96637b2013-05-04 22:12:25 -05004824 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 if (ses == NULL)
4826 return -ENODEV;
4827getDFSRetry:
4828 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4829 (void **) &pSMBr);
4830 if (rc)
4831 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004832
4833 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004834 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004835 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 pSMB->hdr.Tid = ses->ipc_tid;
4837 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004838 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004840 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842
4843 if (ses->capabilities & CAP_UNICODE) {
4844 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4845 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004846 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004847 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004848 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 name_len++; /* trailing null */
4850 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004851 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004852 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004854 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 }
4856
Dan Carpenter65c3b202015-04-30 17:30:24 +03004857 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004858 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004859
Steve French50c2f752007-07-13 00:33:32 +00004860 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004861
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 params = 2 /* level */ + name_len /*includes null */ ;
4863 pSMB->TotalDataCount = 0;
4864 pSMB->DataCount = 0;
4865 pSMB->DataOffset = 0;
4866 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004867 /* BB find exact max SMB PDU from sess structure BB */
4868 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 pSMB->MaxSetupCount = 0;
4870 pSMB->Reserved = 0;
4871 pSMB->Flags = 0;
4872 pSMB->Timeout = 0;
4873 pSMB->Reserved2 = 0;
4874 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004875 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 pSMB->SetupCount = 1;
4877 pSMB->Reserved3 = 0;
4878 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4879 byte_count = params + 3 /* pad */ ;
4880 pSMB->ParameterCount = cpu_to_le16(params);
4881 pSMB->TotalParameterCount = pSMB->ParameterCount;
4882 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004883 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 pSMB->ByteCount = cpu_to_le16(byte_count);
4885
4886 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4888 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004889 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004890 goto GetDFSRefExit;
4891 }
4892 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004894 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004895 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004896 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004897 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004899
Joe Perchesf96637b2013-05-04 22:12:25 -05004900 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4901 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004902
4903 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004904 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4905 le16_to_cpu(pSMBr->t2.DataCount),
4906 num_of_nodes, target_nodes, nls_codepage,
4907 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004908 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004909
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004911 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912
4913 if (rc == -EAGAIN)
4914 goto getDFSRetry;
4915
4916 return rc;
4917}
4918
Steve French20962432005-09-21 22:05:57 -07004919/* Query File System Info such as free space to old servers such as Win 9x */
4920int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004921SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4922 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004923{
4924/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4925 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4926 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4927 FILE_SYSTEM_ALLOC_INFO *response_data;
4928 int rc = 0;
4929 int bytes_returned = 0;
4930 __u16 params, byte_count;
4931
Joe Perchesf96637b2013-05-04 22:12:25 -05004932 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004933oldQFSInfoRetry:
4934 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4935 (void **) &pSMBr);
4936 if (rc)
4937 return rc;
Steve French20962432005-09-21 22:05:57 -07004938
4939 params = 2; /* level */
4940 pSMB->TotalDataCount = 0;
4941 pSMB->MaxParameterCount = cpu_to_le16(2);
4942 pSMB->MaxDataCount = cpu_to_le16(1000);
4943 pSMB->MaxSetupCount = 0;
4944 pSMB->Reserved = 0;
4945 pSMB->Flags = 0;
4946 pSMB->Timeout = 0;
4947 pSMB->Reserved2 = 0;
4948 byte_count = params + 1 /* pad */ ;
4949 pSMB->TotalParameterCount = cpu_to_le16(params);
4950 pSMB->ParameterCount = pSMB->TotalParameterCount;
4951 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4952 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4953 pSMB->DataCount = 0;
4954 pSMB->DataOffset = 0;
4955 pSMB->SetupCount = 1;
4956 pSMB->Reserved3 = 0;
4957 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4958 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004959 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004960 pSMB->ByteCount = cpu_to_le16(byte_count);
4961
4962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4964 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004965 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004966 } else { /* decode response */
4967 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4968
Jeff Layton820a8032011-05-04 08:05:26 -04004969 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004970 rc = -EIO; /* bad smb */
4971 else {
4972 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004973 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004974 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004975
Steve French50c2f752007-07-13 00:33:32 +00004976 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004977 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4978 FSData->f_bsize =
4979 le16_to_cpu(response_data->BytesPerSector) *
4980 le32_to_cpu(response_data->
4981 SectorsPerAllocationUnit);
4982 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004983 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004984 FSData->f_bfree = FSData->f_bavail =
4985 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004986 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4987 (unsigned long long)FSData->f_blocks,
4988 (unsigned long long)FSData->f_bfree,
4989 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004990 }
4991 }
4992 cifs_buf_release(pSMB);
4993
4994 if (rc == -EAGAIN)
4995 goto oldQFSInfoRetry;
4996
4997 return rc;
4998}
4999
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005001CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5002 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003{
5004/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5005 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5006 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5007 FILE_SYSTEM_INFO *response_data;
5008 int rc = 0;
5009 int bytes_returned = 0;
5010 __u16 params, byte_count;
5011
Joe Perchesf96637b2013-05-04 22:12:25 -05005012 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013QFSInfoRetry:
5014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5015 (void **) &pSMBr);
5016 if (rc)
5017 return rc;
5018
5019 params = 2; /* level */
5020 pSMB->TotalDataCount = 0;
5021 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005022 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023 pSMB->MaxSetupCount = 0;
5024 pSMB->Reserved = 0;
5025 pSMB->Flags = 0;
5026 pSMB->Timeout = 0;
5027 pSMB->Reserved2 = 0;
5028 byte_count = params + 1 /* pad */ ;
5029 pSMB->TotalParameterCount = cpu_to_le16(params);
5030 pSMB->ParameterCount = pSMB->TotalParameterCount;
5031 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005032 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 pSMB->DataCount = 0;
5034 pSMB->DataOffset = 0;
5035 pSMB->SetupCount = 1;
5036 pSMB->Reserved3 = 0;
5037 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005039 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 pSMB->ByteCount = cpu_to_le16(byte_count);
5041
5042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5044 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005045 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005047 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048
Jeff Layton820a8032011-05-04 08:05:26 -04005049 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 rc = -EIO; /* bad smb */
5051 else {
5052 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053
5054 response_data =
5055 (FILE_SYSTEM_INFO
5056 *) (((char *) &pSMBr->hdr.Protocol) +
5057 data_offset);
5058 FSData->f_bsize =
5059 le32_to_cpu(response_data->BytesPerSector) *
5060 le32_to_cpu(response_data->
5061 SectorsPerAllocationUnit);
5062 FSData->f_blocks =
5063 le64_to_cpu(response_data->TotalAllocationUnits);
5064 FSData->f_bfree = FSData->f_bavail =
5065 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005066 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5067 (unsigned long long)FSData->f_blocks,
5068 (unsigned long long)FSData->f_bfree,
5069 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 }
5071 }
5072 cifs_buf_release(pSMB);
5073
5074 if (rc == -EAGAIN)
5075 goto QFSInfoRetry;
5076
5077 return rc;
5078}
5079
5080int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005081CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082{
5083/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5084 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5085 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5086 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5087 int rc = 0;
5088 int bytes_returned = 0;
5089 __u16 params, byte_count;
5090
Joe Perchesf96637b2013-05-04 22:12:25 -05005091 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092QFSAttributeRetry:
5093 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5094 (void **) &pSMBr);
5095 if (rc)
5096 return rc;
5097
5098 params = 2; /* level */
5099 pSMB->TotalDataCount = 0;
5100 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005101 /* BB find exact max SMB PDU from sess structure BB */
5102 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 pSMB->MaxSetupCount = 0;
5104 pSMB->Reserved = 0;
5105 pSMB->Flags = 0;
5106 pSMB->Timeout = 0;
5107 pSMB->Reserved2 = 0;
5108 byte_count = params + 1 /* pad */ ;
5109 pSMB->TotalParameterCount = cpu_to_le16(params);
5110 pSMB->ParameterCount = pSMB->TotalParameterCount;
5111 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005112 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 pSMB->DataCount = 0;
5114 pSMB->DataOffset = 0;
5115 pSMB->SetupCount = 1;
5116 pSMB->Reserved3 = 0;
5117 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5118 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005119 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 pSMB->ByteCount = cpu_to_le16(byte_count);
5121
5122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5124 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005125 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 } else { /* decode response */
5127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5128
Jeff Layton820a8032011-05-04 08:05:26 -04005129 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005130 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 rc = -EIO; /* bad smb */
5132 } else {
5133 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5134 response_data =
5135 (FILE_SYSTEM_ATTRIBUTE_INFO
5136 *) (((char *) &pSMBr->hdr.Protocol) +
5137 data_offset);
5138 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005139 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 }
5141 }
5142 cifs_buf_release(pSMB);
5143
5144 if (rc == -EAGAIN)
5145 goto QFSAttributeRetry;
5146
5147 return rc;
5148}
5149
5150int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005151CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152{
5153/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5154 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5155 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5156 FILE_SYSTEM_DEVICE_INFO *response_data;
5157 int rc = 0;
5158 int bytes_returned = 0;
5159 __u16 params, byte_count;
5160
Joe Perchesf96637b2013-05-04 22:12:25 -05005161 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162QFSDeviceRetry:
5163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5164 (void **) &pSMBr);
5165 if (rc)
5166 return rc;
5167
5168 params = 2; /* level */
5169 pSMB->TotalDataCount = 0;
5170 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005171 /* BB find exact max SMB PDU from sess structure BB */
5172 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 pSMB->MaxSetupCount = 0;
5174 pSMB->Reserved = 0;
5175 pSMB->Flags = 0;
5176 pSMB->Timeout = 0;
5177 pSMB->Reserved2 = 0;
5178 byte_count = params + 1 /* pad */ ;
5179 pSMB->TotalParameterCount = cpu_to_le16(params);
5180 pSMB->ParameterCount = pSMB->TotalParameterCount;
5181 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005182 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183
5184 pSMB->DataCount = 0;
5185 pSMB->DataOffset = 0;
5186 pSMB->SetupCount = 1;
5187 pSMB->Reserved3 = 0;
5188 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5189 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005190 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 pSMB->ByteCount = cpu_to_le16(byte_count);
5192
5193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5194 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5195 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005196 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 } else { /* decode response */
5198 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5199
Jeff Layton820a8032011-05-04 08:05:26 -04005200 if (rc || get_bcc(&pSMBr->hdr) <
5201 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 rc = -EIO; /* bad smb */
5203 else {
5204 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5205 response_data =
Steve French737b7582005-04-28 22:41:06 -07005206 (FILE_SYSTEM_DEVICE_INFO *)
5207 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 data_offset);
5209 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005210 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 }
5212 }
5213 cifs_buf_release(pSMB);
5214
5215 if (rc == -EAGAIN)
5216 goto QFSDeviceRetry;
5217
5218 return rc;
5219}
5220
5221int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005222CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223{
5224/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5225 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5226 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5227 FILE_SYSTEM_UNIX_INFO *response_data;
5228 int rc = 0;
5229 int bytes_returned = 0;
5230 __u16 params, byte_count;
5231
Joe Perchesf96637b2013-05-04 22:12:25 -05005232 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005234 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5235 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 if (rc)
5237 return rc;
5238
5239 params = 2; /* level */
5240 pSMB->TotalDataCount = 0;
5241 pSMB->DataCount = 0;
5242 pSMB->DataOffset = 0;
5243 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005244 /* BB find exact max SMB PDU from sess structure BB */
5245 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 pSMB->MaxSetupCount = 0;
5247 pSMB->Reserved = 0;
5248 pSMB->Flags = 0;
5249 pSMB->Timeout = 0;
5250 pSMB->Reserved2 = 0;
5251 byte_count = params + 1 /* pad */ ;
5252 pSMB->ParameterCount = cpu_to_le16(params);
5253 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005254 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5255 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 pSMB->SetupCount = 1;
5257 pSMB->Reserved3 = 0;
5258 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5259 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005260 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 pSMB->ByteCount = cpu_to_le16(byte_count);
5262
5263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5265 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005266 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 } else { /* decode response */
5268 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5269
Jeff Layton820a8032011-05-04 08:05:26 -04005270 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 rc = -EIO; /* bad smb */
5272 } else {
5273 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5274 response_data =
5275 (FILE_SYSTEM_UNIX_INFO
5276 *) (((char *) &pSMBr->hdr.Protocol) +
5277 data_offset);
5278 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005279 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 }
5281 }
5282 cifs_buf_release(pSMB);
5283
5284 if (rc == -EAGAIN)
5285 goto QFSUnixRetry;
5286
5287
5288 return rc;
5289}
5290
Jeremy Allisonac670552005-06-22 17:26:35 -07005291int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005292CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005293{
5294/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5295 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5296 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5297 int rc = 0;
5298 int bytes_returned = 0;
5299 __u16 params, param_offset, offset, byte_count;
5300
Joe Perchesf96637b2013-05-04 22:12:25 -05005301 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005302SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005303 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005304 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5305 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005306 if (rc)
5307 return rc;
5308
5309 params = 4; /* 2 bytes zero followed by info level. */
5310 pSMB->MaxSetupCount = 0;
5311 pSMB->Reserved = 0;
5312 pSMB->Flags = 0;
5313 pSMB->Timeout = 0;
5314 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005315 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5316 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005317 offset = param_offset + params;
5318
5319 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005320 /* BB find exact max SMB PDU from sess structure BB */
5321 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005322 pSMB->SetupCount = 1;
5323 pSMB->Reserved3 = 0;
5324 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5325 byte_count = 1 /* pad */ + params + 12;
5326
5327 pSMB->DataCount = cpu_to_le16(12);
5328 pSMB->ParameterCount = cpu_to_le16(params);
5329 pSMB->TotalDataCount = pSMB->DataCount;
5330 pSMB->TotalParameterCount = pSMB->ParameterCount;
5331 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5332 pSMB->DataOffset = cpu_to_le16(offset);
5333
5334 /* Params. */
5335 pSMB->FileNum = 0;
5336 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5337
5338 /* Data. */
5339 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5340 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5341 pSMB->ClientUnixCap = cpu_to_le64(cap);
5342
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005343 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005344 pSMB->ByteCount = cpu_to_le16(byte_count);
5345
5346 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5347 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5348 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005349 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005350 } else { /* decode response */
5351 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005352 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005353 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005354 }
5355 cifs_buf_release(pSMB);
5356
5357 if (rc == -EAGAIN)
5358 goto SETFSUnixRetry;
5359
5360 return rc;
5361}
5362
5363
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364
5365int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005366CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005367 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368{
5369/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5370 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5371 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5372 FILE_SYSTEM_POSIX_INFO *response_data;
5373 int rc = 0;
5374 int bytes_returned = 0;
5375 __u16 params, byte_count;
5376
Joe Perchesf96637b2013-05-04 22:12:25 -05005377 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378QFSPosixRetry:
5379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5380 (void **) &pSMBr);
5381 if (rc)
5382 return rc;
5383
5384 params = 2; /* level */
5385 pSMB->TotalDataCount = 0;
5386 pSMB->DataCount = 0;
5387 pSMB->DataOffset = 0;
5388 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005389 /* BB find exact max SMB PDU from sess structure BB */
5390 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 pSMB->MaxSetupCount = 0;
5392 pSMB->Reserved = 0;
5393 pSMB->Flags = 0;
5394 pSMB->Timeout = 0;
5395 pSMB->Reserved2 = 0;
5396 byte_count = params + 1 /* pad */ ;
5397 pSMB->ParameterCount = cpu_to_le16(params);
5398 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005399 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5400 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 pSMB->SetupCount = 1;
5402 pSMB->Reserved3 = 0;
5403 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5404 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005405 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 pSMB->ByteCount = cpu_to_le16(byte_count);
5407
5408 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5409 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5410 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005411 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 } else { /* decode response */
5413 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5414
Jeff Layton820a8032011-05-04 08:05:26 -04005415 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 rc = -EIO; /* bad smb */
5417 } else {
5418 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5419 response_data =
5420 (FILE_SYSTEM_POSIX_INFO
5421 *) (((char *) &pSMBr->hdr.Protocol) +
5422 data_offset);
5423 FSData->f_bsize =
5424 le32_to_cpu(response_data->BlockSize);
5425 FSData->f_blocks =
5426 le64_to_cpu(response_data->TotalBlocks);
5427 FSData->f_bfree =
5428 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005429 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 FSData->f_bavail = FSData->f_bfree;
5431 } else {
5432 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005433 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 }
Steve French790fe572007-07-07 19:25:05 +00005435 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005437 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005438 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005440 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 }
5442 }
5443 cifs_buf_release(pSMB);
5444
5445 if (rc == -EAGAIN)
5446 goto QFSPosixRetry;
5447
5448 return rc;
5449}
5450
5451
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005452/*
5453 * We can not use write of zero bytes trick to set file size due to need for
5454 * large file support. Also note that this SetPathInfo is preferred to
5455 * SetFileInfo based method in next routine which is only needed to work around
5456 * a sharing violation bugin Samba which this routine can run into.
5457 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005459CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005460 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5461 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462{
5463 struct smb_com_transaction2_spi_req *pSMB = NULL;
5464 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5465 struct file_end_of_file_info *parm_data;
5466 int name_len;
5467 int rc = 0;
5468 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005469 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005470
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 __u16 params, byte_count, data_count, param_offset, offset;
5472
Joe Perchesf96637b2013-05-04 22:12:25 -05005473 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474SetEOFRetry:
5475 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5476 (void **) &pSMBr);
5477 if (rc)
5478 return rc;
5479
5480 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5481 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005482 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5483 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 name_len++; /* trailing null */
5485 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005486 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005487 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005489 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 }
5491 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005492 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005494 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 pSMB->MaxSetupCount = 0;
5496 pSMB->Reserved = 0;
5497 pSMB->Flags = 0;
5498 pSMB->Timeout = 0;
5499 pSMB->Reserved2 = 0;
5500 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005501 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005503 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005504 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5505 pSMB->InformationLevel =
5506 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5507 else
5508 pSMB->InformationLevel =
5509 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5510 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5512 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005513 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 else
5515 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005516 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 }
5518
5519 parm_data =
5520 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5521 offset);
5522 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5523 pSMB->DataOffset = cpu_to_le16(offset);
5524 pSMB->SetupCount = 1;
5525 pSMB->Reserved3 = 0;
5526 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5527 byte_count = 3 /* pad */ + params + data_count;
5528 pSMB->DataCount = cpu_to_le16(data_count);
5529 pSMB->TotalDataCount = pSMB->DataCount;
5530 pSMB->ParameterCount = cpu_to_le16(params);
5531 pSMB->TotalParameterCount = pSMB->ParameterCount;
5532 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005533 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 parm_data->FileSize = cpu_to_le64(size);
5535 pSMB->ByteCount = cpu_to_le16(byte_count);
5536 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5537 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005538 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005539 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
5541 cifs_buf_release(pSMB);
5542
5543 if (rc == -EAGAIN)
5544 goto SetEOFRetry;
5545
5546 return rc;
5547}
5548
5549int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005550CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5551 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552{
5553 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 struct file_end_of_file_info *parm_data;
5555 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 __u16 params, param_offset, offset, byte_count, count;
5557
Joe Perchesf96637b2013-05-04 22:12:25 -05005558 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5559 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005560 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5561
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 if (rc)
5563 return rc;
5564
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005565 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5566 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005567
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 params = 6;
5569 pSMB->MaxSetupCount = 0;
5570 pSMB->Reserved = 0;
5571 pSMB->Flags = 0;
5572 pSMB->Timeout = 0;
5573 pSMB->Reserved2 = 0;
5574 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5575 offset = param_offset + params;
5576
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 count = sizeof(struct file_end_of_file_info);
5578 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005579 /* BB find exact max SMB PDU from sess structure BB */
5580 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 pSMB->SetupCount = 1;
5582 pSMB->Reserved3 = 0;
5583 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5584 byte_count = 3 /* pad */ + params + count;
5585 pSMB->DataCount = cpu_to_le16(count);
5586 pSMB->ParameterCount = cpu_to_le16(params);
5587 pSMB->TotalDataCount = pSMB->DataCount;
5588 pSMB->TotalParameterCount = pSMB->ParameterCount;
5589 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5590 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005591 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5592 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 pSMB->DataOffset = cpu_to_le16(offset);
5594 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005595 pSMB->Fid = cfile->fid.netfid;
5596 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5598 pSMB->InformationLevel =
5599 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5600 else
5601 pSMB->InformationLevel =
5602 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005603 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5605 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005606 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 else
5608 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005609 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 }
5611 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005612 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005614 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005615 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005617 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5618 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 }
5620
Steve French50c2f752007-07-13 00:33:32 +00005621 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 since file handle passed in no longer valid */
5623
5624 return rc;
5625}
5626
Steve French50c2f752007-07-13 00:33:32 +00005627/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 an open handle, rather than by pathname - this is awkward due to
5629 potential access conflicts on the open, but it is unavoidable for these
5630 old servers since the only other choice is to go from 100 nanosecond DCE
5631 time and resort to the original setpathinfo level which takes the ancient
5632 DOS time format with 2 second granularity */
5633int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005634CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005635 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636{
5637 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 char *data_offset;
5639 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 __u16 params, param_offset, offset, byte_count, count;
5641
Joe Perchesf96637b2013-05-04 22:12:25 -05005642 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005643 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5644
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 if (rc)
5646 return rc;
5647
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005648 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5649 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005650
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 params = 6;
5652 pSMB->MaxSetupCount = 0;
5653 pSMB->Reserved = 0;
5654 pSMB->Flags = 0;
5655 pSMB->Timeout = 0;
5656 pSMB->Reserved2 = 0;
5657 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5658 offset = param_offset + params;
5659
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005660 data_offset = (char *)pSMB +
5661 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
Steve French26f57362007-08-30 22:09:15 +00005663 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005665 /* BB find max SMB PDU from sess */
5666 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 pSMB->SetupCount = 1;
5668 pSMB->Reserved3 = 0;
5669 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5670 byte_count = 3 /* pad */ + params + count;
5671 pSMB->DataCount = cpu_to_le16(count);
5672 pSMB->ParameterCount = cpu_to_le16(params);
5673 pSMB->TotalDataCount = pSMB->DataCount;
5674 pSMB->TotalParameterCount = pSMB->ParameterCount;
5675 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5676 pSMB->DataOffset = cpu_to_le16(offset);
5677 pSMB->Fid = fid;
5678 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5679 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5680 else
5681 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5682 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005683 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005685 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005686 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005687 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005688 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005689 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5690 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691
Steve French50c2f752007-07-13 00:33:32 +00005692 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 since file handle passed in no longer valid */
5694
5695 return rc;
5696}
5697
Jeff Layton6d22f092008-09-23 11:48:35 -04005698int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005699CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005700 bool delete_file, __u16 fid, __u32 pid_of_opener)
5701{
5702 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5703 char *data_offset;
5704 int rc = 0;
5705 __u16 params, param_offset, offset, byte_count, count;
5706
Joe Perchesf96637b2013-05-04 22:12:25 -05005707 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005708 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5709
5710 if (rc)
5711 return rc;
5712
5713 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5714 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5715
5716 params = 6;
5717 pSMB->MaxSetupCount = 0;
5718 pSMB->Reserved = 0;
5719 pSMB->Flags = 0;
5720 pSMB->Timeout = 0;
5721 pSMB->Reserved2 = 0;
5722 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5723 offset = param_offset + params;
5724
5725 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5726
5727 count = 1;
5728 pSMB->MaxParameterCount = cpu_to_le16(2);
5729 /* BB find max SMB PDU from sess */
5730 pSMB->MaxDataCount = cpu_to_le16(1000);
5731 pSMB->SetupCount = 1;
5732 pSMB->Reserved3 = 0;
5733 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5734 byte_count = 3 /* pad */ + params + count;
5735 pSMB->DataCount = cpu_to_le16(count);
5736 pSMB->ParameterCount = cpu_to_le16(params);
5737 pSMB->TotalDataCount = pSMB->DataCount;
5738 pSMB->TotalParameterCount = pSMB->ParameterCount;
5739 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5740 pSMB->DataOffset = cpu_to_le16(offset);
5741 pSMB->Fid = fid;
5742 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5743 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005744 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005745 pSMB->ByteCount = cpu_to_le16(byte_count);
5746 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005747 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005748 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005749 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005750 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005751
5752 return rc;
5753}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754
5755int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005756CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005757 const char *fileName, const FILE_BASIC_INFO *data,
5758 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759{
5760 TRANSACTION2_SPI_REQ *pSMB = NULL;
5761 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5762 int name_len;
5763 int rc = 0;
5764 int bytes_returned = 0;
5765 char *data_offset;
5766 __u16 params, param_offset, offset, byte_count, count;
5767
Joe Perchesf96637b2013-05-04 22:12:25 -05005768 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769
5770SetTimesRetry:
5771 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5772 (void **) &pSMBr);
5773 if (rc)
5774 return rc;
5775
5776 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5777 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005778 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5779 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 name_len++; /* trailing null */
5781 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005782 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 name_len = strnlen(fileName, PATH_MAX);
5784 name_len++; /* trailing null */
5785 strncpy(pSMB->FileName, fileName, name_len);
5786 }
5787
5788 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005789 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005791 /* BB find max SMB PDU from sess structure BB */
5792 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793 pSMB->MaxSetupCount = 0;
5794 pSMB->Reserved = 0;
5795 pSMB->Flags = 0;
5796 pSMB->Timeout = 0;
5797 pSMB->Reserved2 = 0;
5798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005799 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 offset = param_offset + params;
5801 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5802 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5803 pSMB->DataOffset = cpu_to_le16(offset);
5804 pSMB->SetupCount = 1;
5805 pSMB->Reserved3 = 0;
5806 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5807 byte_count = 3 /* pad */ + params + count;
5808
5809 pSMB->DataCount = cpu_to_le16(count);
5810 pSMB->ParameterCount = cpu_to_le16(params);
5811 pSMB->TotalDataCount = pSMB->DataCount;
5812 pSMB->TotalParameterCount = pSMB->ParameterCount;
5813 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5814 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5815 else
5816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5817 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005818 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005819 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 pSMB->ByteCount = cpu_to_le16(byte_count);
5821 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5822 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005823 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005824 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825
5826 cifs_buf_release(pSMB);
5827
5828 if (rc == -EAGAIN)
5829 goto SetTimesRetry;
5830
5831 return rc;
5832}
5833
5834/* Can not be used to set time stamps yet (due to old DOS time format) */
5835/* Can be used to set attributes */
5836#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5837 handling it anyway and NT4 was what we thought it would be needed for
5838 Do not delete it until we prove whether needed for Win9x though */
5839int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005840CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 __u16 dos_attrs, const struct nls_table *nls_codepage)
5842{
5843 SETATTR_REQ *pSMB = NULL;
5844 SETATTR_RSP *pSMBr = NULL;
5845 int rc = 0;
5846 int bytes_returned;
5847 int name_len;
5848
Joe Perchesf96637b2013-05-04 22:12:25 -05005849 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850
5851SetAttrLgcyRetry:
5852 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5853 (void **) &pSMBr);
5854 if (rc)
5855 return rc;
5856
5857 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5858 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005859 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5860 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 name_len++; /* trailing null */
5862 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005863 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 name_len = strnlen(fileName, PATH_MAX);
5865 name_len++; /* trailing null */
5866 strncpy(pSMB->fileName, fileName, name_len);
5867 }
5868 pSMB->attr = cpu_to_le16(dos_attrs);
5869 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005870 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005874 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005875 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
5877 cifs_buf_release(pSMB);
5878
5879 if (rc == -EAGAIN)
5880 goto SetAttrLgcyRetry;
5881
5882 return rc;
5883}
5884#endif /* temporarily unneeded SetAttr legacy function */
5885
Jeff Layton654cf142009-07-09 20:02:49 -04005886static void
5887cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5888 const struct cifs_unix_set_info_args *args)
5889{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005890 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005891 u64 mode = args->mode;
5892
Eric W. Biederman49418b22013-02-06 00:57:56 -08005893 if (uid_valid(args->uid))
5894 uid = from_kuid(&init_user_ns, args->uid);
5895 if (gid_valid(args->gid))
5896 gid = from_kgid(&init_user_ns, args->gid);
5897
Jeff Layton654cf142009-07-09 20:02:49 -04005898 /*
5899 * Samba server ignores set of file size to zero due to bugs in some
5900 * older clients, but we should be precise - we use SetFileSize to
5901 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005902 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005903 * zero instead of -1 here
5904 */
5905 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5906 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5907 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5908 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5909 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005910 data_offset->Uid = cpu_to_le64(uid);
5911 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005912 /* better to leave device as zero when it is */
5913 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5914 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5915 data_offset->Permissions = cpu_to_le64(mode);
5916
5917 if (S_ISREG(mode))
5918 data_offset->Type = cpu_to_le32(UNIX_FILE);
5919 else if (S_ISDIR(mode))
5920 data_offset->Type = cpu_to_le32(UNIX_DIR);
5921 else if (S_ISLNK(mode))
5922 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5923 else if (S_ISCHR(mode))
5924 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5925 else if (S_ISBLK(mode))
5926 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5927 else if (S_ISFIFO(mode))
5928 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5929 else if (S_ISSOCK(mode))
5930 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5931}
5932
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005934CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005935 const struct cifs_unix_set_info_args *args,
5936 u16 fid, u32 pid_of_opener)
5937{
5938 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005939 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005940 int rc = 0;
5941 u16 params, param_offset, offset, byte_count, count;
5942
Joe Perchesf96637b2013-05-04 22:12:25 -05005943 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005944 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5945
5946 if (rc)
5947 return rc;
5948
5949 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5950 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5951
5952 params = 6;
5953 pSMB->MaxSetupCount = 0;
5954 pSMB->Reserved = 0;
5955 pSMB->Flags = 0;
5956 pSMB->Timeout = 0;
5957 pSMB->Reserved2 = 0;
5958 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5959 offset = param_offset + params;
5960
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005961 data_offset = (char *)pSMB +
5962 offsetof(struct smb_hdr, Protocol) + offset;
5963
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005964 count = sizeof(FILE_UNIX_BASIC_INFO);
5965
5966 pSMB->MaxParameterCount = cpu_to_le16(2);
5967 /* BB find max SMB PDU from sess */
5968 pSMB->MaxDataCount = cpu_to_le16(1000);
5969 pSMB->SetupCount = 1;
5970 pSMB->Reserved3 = 0;
5971 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5972 byte_count = 3 /* pad */ + params + count;
5973 pSMB->DataCount = cpu_to_le16(count);
5974 pSMB->ParameterCount = cpu_to_le16(params);
5975 pSMB->TotalDataCount = pSMB->DataCount;
5976 pSMB->TotalParameterCount = pSMB->ParameterCount;
5977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5978 pSMB->DataOffset = cpu_to_le16(offset);
5979 pSMB->Fid = fid;
5980 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5981 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005982 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005983 pSMB->ByteCount = cpu_to_le16(byte_count);
5984
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005985 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005986
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005987 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005988 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005989 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005990 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5991 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005992
5993 /* Note: On -EAGAIN error only caller can retry on handle based calls
5994 since file handle passed in no longer valid */
5995
5996 return rc;
5997}
5998
5999int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006000CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006001 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006002 const struct cifs_unix_set_info_args *args,
6003 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004{
6005 TRANSACTION2_SPI_REQ *pSMB = NULL;
6006 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6007 int name_len;
6008 int rc = 0;
6009 int bytes_returned = 0;
6010 FILE_UNIX_BASIC_INFO *data_offset;
6011 __u16 params, param_offset, offset, count, byte_count;
6012
Joe Perchesf96637b2013-05-04 22:12:25 -05006013 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014setPermsRetry:
6015 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6016 (void **) &pSMBr);
6017 if (rc)
6018 return rc;
6019
6020 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6021 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006022 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006023 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024 name_len++; /* trailing null */
6025 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006026 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006027 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006029 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030 }
6031
6032 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006033 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006035 /* BB find max SMB PDU from sess structure BB */
6036 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037 pSMB->MaxSetupCount = 0;
6038 pSMB->Reserved = 0;
6039 pSMB->Flags = 0;
6040 pSMB->Timeout = 0;
6041 pSMB->Reserved2 = 0;
6042 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006043 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 offset = param_offset + params;
6045 data_offset =
6046 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6047 offset);
6048 memset(data_offset, 0, count);
6049 pSMB->DataOffset = cpu_to_le16(offset);
6050 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6051 pSMB->SetupCount = 1;
6052 pSMB->Reserved3 = 0;
6053 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6054 byte_count = 3 /* pad */ + params + count;
6055 pSMB->ParameterCount = cpu_to_le16(params);
6056 pSMB->DataCount = cpu_to_le16(count);
6057 pSMB->TotalParameterCount = pSMB->ParameterCount;
6058 pSMB->TotalDataCount = pSMB->DataCount;
6059 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6060 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006061 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006062
Jeff Layton654cf142009-07-09 20:02:49 -04006063 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
6065 pSMB->ByteCount = cpu_to_le16(byte_count);
6066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006068 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006069 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
Steve French0d817bc2008-05-22 02:02:03 +00006071 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 if (rc == -EAGAIN)
6073 goto setPermsRetry;
6074 return rc;
6075}
6076
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006078/*
6079 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6080 * function used by listxattr and getxattr type calls. When ea_name is set,
6081 * it looks for that attribute name and stuffs that value into the EAData
6082 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6083 * buffer. In both cases, the return value is either the length of the
6084 * resulting data or a negative error code. If EAData is a NULL pointer then
6085 * the data isn't copied to it, but the length is returned.
6086 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006088CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006089 const unsigned char *searchName, const unsigned char *ea_name,
6090 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006091 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092{
6093 /* BB assumes one setup word */
6094 TRANSACTION2_QPI_REQ *pSMB = NULL;
6095 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006096 int remap = cifs_remap(cifs_sb);
6097 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098 int rc = 0;
6099 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006100 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006101 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006102 struct fea *temp_fea;
6103 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006104 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006105 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006106 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107
Joe Perchesf96637b2013-05-04 22:12:25 -05006108 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109QAllEAsRetry:
6110 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6111 (void **) &pSMBr);
6112 if (rc)
6113 return rc;
6114
6115 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006116 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006117 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6118 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006119 list_len++; /* trailing null */
6120 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006122 list_len = strnlen(searchName, PATH_MAX);
6123 list_len++; /* trailing null */
6124 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 }
6126
Jeff Layton6e462b92010-02-10 16:18:26 -05006127 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128 pSMB->TotalDataCount = 0;
6129 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006130 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006131 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 pSMB->MaxSetupCount = 0;
6133 pSMB->Reserved = 0;
6134 pSMB->Flags = 0;
6135 pSMB->Timeout = 0;
6136 pSMB->Reserved2 = 0;
6137 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006138 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139 pSMB->DataCount = 0;
6140 pSMB->DataOffset = 0;
6141 pSMB->SetupCount = 1;
6142 pSMB->Reserved3 = 0;
6143 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6144 byte_count = params + 1 /* pad */ ;
6145 pSMB->TotalParameterCount = cpu_to_le16(params);
6146 pSMB->ParameterCount = pSMB->TotalParameterCount;
6147 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6148 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006149 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 pSMB->ByteCount = cpu_to_le16(byte_count);
6151
6152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6153 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6154 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006155 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006156 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006158
6159
6160 /* BB also check enough total bytes returned */
6161 /* BB we need to improve the validity checking
6162 of these trans2 responses */
6163
6164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006165 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006166 rc = -EIO; /* bad smb */
6167 goto QAllEAsOut;
6168 }
6169
6170 /* check that length of list is not more than bcc */
6171 /* check that each entry does not go beyond length
6172 of list */
6173 /* check that each element of each entry does not
6174 go beyond end of list */
6175 /* validate_trans2_offsets() */
6176 /* BB check if start of smb + data_offset > &bcc+ bcc */
6177
6178 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6179 ea_response_data = (struct fealist *)
6180 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6181
Jeff Layton6e462b92010-02-10 16:18:26 -05006182 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006183 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006184 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006185 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006186 /* didn't find the named attribute */
6187 if (ea_name)
6188 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006189 goto QAllEAsOut;
6190 }
6191
Jeff Layton0cd126b2010-02-10 16:18:26 -05006192 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006193 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006194 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006195 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006196 rc = -EIO;
6197 goto QAllEAsOut;
6198 }
6199
Jeff Laytonf0d38682010-02-10 16:18:26 -05006200 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006201 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006202 temp_fea = ea_response_data->list;
6203 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006204 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006205 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006206 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006207
Jeff Layton6e462b92010-02-10 16:18:26 -05006208 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006209 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006210 /* make sure we can read name_len and value_len */
6211 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006212 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006213 rc = -EIO;
6214 goto QAllEAsOut;
6215 }
6216
6217 name_len = temp_fea->name_len;
6218 value_len = le16_to_cpu(temp_fea->value_len);
6219 list_len -= name_len + 1 + value_len;
6220 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006221 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006222 rc = -EIO;
6223 goto QAllEAsOut;
6224 }
6225
Jeff Layton31c05192010-02-10 16:18:26 -05006226 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006227 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006228 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006229 temp_ptr += name_len + 1;
6230 rc = value_len;
6231 if (buf_size == 0)
6232 goto QAllEAsOut;
6233 if ((size_t)value_len > buf_size) {
6234 rc = -ERANGE;
6235 goto QAllEAsOut;
6236 }
6237 memcpy(EAData, temp_ptr, value_len);
6238 goto QAllEAsOut;
6239 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006240 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006241 /* account for prefix user. and trailing null */
6242 rc += (5 + 1 + name_len);
6243 if (rc < (int) buf_size) {
6244 memcpy(EAData, "user.", 5);
6245 EAData += 5;
6246 memcpy(EAData, temp_ptr, name_len);
6247 EAData += name_len;
6248 /* null terminate name */
6249 *EAData = 0;
6250 ++EAData;
6251 } else if (buf_size == 0) {
6252 /* skip copy - calc size only */
6253 } else {
6254 /* stop before overrun buffer */
6255 rc = -ERANGE;
6256 break;
6257 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006258 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006259 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006260 temp_fea = (struct fea *)temp_ptr;
6261 }
6262
Jeff Layton31c05192010-02-10 16:18:26 -05006263 /* didn't find the named attribute */
6264 if (ea_name)
6265 rc = -ENODATA;
6266
Jeff Laytonf0d38682010-02-10 16:18:26 -05006267QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006268 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 if (rc == -EAGAIN)
6270 goto QAllEAsRetry;
6271
6272 return (ssize_t)rc;
6273}
6274
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006276CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6277 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006278 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006279 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280{
6281 struct smb_com_transaction2_spi_req *pSMB = NULL;
6282 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6283 struct fealist *parm_data;
6284 int name_len;
6285 int rc = 0;
6286 int bytes_returned = 0;
6287 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006288 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289
Joe Perchesf96637b2013-05-04 22:12:25 -05006290 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291SetEARetry:
6292 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6293 (void **) &pSMBr);
6294 if (rc)
6295 return rc;
6296
6297 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6298 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006299 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6300 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301 name_len++; /* trailing null */
6302 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006303 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304 name_len = strnlen(fileName, PATH_MAX);
6305 name_len++; /* trailing null */
6306 strncpy(pSMB->FileName, fileName, name_len);
6307 }
6308
6309 params = 6 + name_len;
6310
6311 /* done calculating parms using name_len of file name,
6312 now use name_len to calculate length of ea name
6313 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006314 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 name_len = 0;
6316 else
Steve French50c2f752007-07-13 00:33:32 +00006317 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006319 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006321 /* BB find max SMB PDU from sess */
6322 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 pSMB->MaxSetupCount = 0;
6324 pSMB->Reserved = 0;
6325 pSMB->Flags = 0;
6326 pSMB->Timeout = 0;
6327 pSMB->Reserved2 = 0;
6328 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006329 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 offset = param_offset + params;
6331 pSMB->InformationLevel =
6332 cpu_to_le16(SMB_SET_FILE_EA);
6333
6334 parm_data =
6335 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6336 offset);
6337 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6338 pSMB->DataOffset = cpu_to_le16(offset);
6339 pSMB->SetupCount = 1;
6340 pSMB->Reserved3 = 0;
6341 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6342 byte_count = 3 /* pad */ + params + count;
6343 pSMB->DataCount = cpu_to_le16(count);
6344 parm_data->list_len = cpu_to_le32(count);
6345 parm_data->list[0].EA_flags = 0;
6346 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006347 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006349 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006350 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351 parm_data->list[0].name[name_len] = 0;
6352 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6353 /* caller ensures that ea_value_len is less than 64K but
6354 we need to ensure that it fits within the smb */
6355
Steve French50c2f752007-07-13 00:33:32 +00006356 /*BB add length check to see if it would fit in
6357 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006358 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6359 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006360 memcpy(parm_data->list[0].name+name_len+1,
6361 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362
6363 pSMB->TotalDataCount = pSMB->DataCount;
6364 pSMB->ParameterCount = cpu_to_le16(params);
6365 pSMB->TotalParameterCount = pSMB->ParameterCount;
6366 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006367 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 pSMB->ByteCount = cpu_to_le16(byte_count);
6369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006371 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006372 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373
6374 cifs_buf_release(pSMB);
6375
6376 if (rc == -EAGAIN)
6377 goto SetEARetry;
6378
6379 return rc;
6380}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381#endif
Steve French0eff0e22011-02-24 05:39:23 +00006382
6383#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6384/*
6385 * Years ago the kernel added a "dnotify" function for Samba server,
6386 * to allow network clients (such as Windows) to display updated
6387 * lists of files in directory listings automatically when
6388 * files are added by one user when another user has the
6389 * same directory open on their desktop. The Linux cifs kernel
6390 * client hooked into the kernel side of this interface for
6391 * the same reason, but ironically when the VFS moved from
6392 * "dnotify" to "inotify" it became harder to plug in Linux
6393 * network file system clients (the most obvious use case
6394 * for notify interfaces is when multiple users can update
6395 * the contents of the same directory - exactly what network
6396 * file systems can do) although the server (Samba) could
6397 * still use it. For the short term we leave the worker
6398 * function ifdeffed out (below) until inotify is fixed
6399 * in the VFS to make it easier to plug in network file
6400 * system clients. If inotify turns out to be permanently
6401 * incompatible for network fs clients, we could instead simply
6402 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6403 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006404int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006405 const int notify_subdirs, const __u16 netfid,
6406 __u32 filter, struct file *pfile, int multishot,
6407 const struct nls_table *nls_codepage)
6408{
6409 int rc = 0;
6410 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6411 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6412 struct dir_notify_req *dnotify_req;
6413 int bytes_returned;
6414
Joe Perchesf96637b2013-05-04 22:12:25 -05006415 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006416 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6417 (void **) &pSMBr);
6418 if (rc)
6419 return rc;
6420
6421 pSMB->TotalParameterCount = 0 ;
6422 pSMB->TotalDataCount = 0;
6423 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006424 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006425 pSMB->MaxSetupCount = 4;
6426 pSMB->Reserved = 0;
6427 pSMB->ParameterOffset = 0;
6428 pSMB->DataCount = 0;
6429 pSMB->DataOffset = 0;
6430 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6431 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6432 pSMB->ParameterCount = pSMB->TotalParameterCount;
6433 if (notify_subdirs)
6434 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6435 pSMB->Reserved2 = 0;
6436 pSMB->CompletionFilter = cpu_to_le32(filter);
6437 pSMB->Fid = netfid; /* file handle always le */
6438 pSMB->ByteCount = 0;
6439
6440 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6441 (struct smb_hdr *)pSMBr, &bytes_returned,
6442 CIFS_ASYNC_OP);
6443 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006444 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006445 } else {
6446 /* Add file to outstanding requests */
6447 /* BB change to kmem cache alloc */
6448 dnotify_req = kmalloc(
6449 sizeof(struct dir_notify_req),
6450 GFP_KERNEL);
6451 if (dnotify_req) {
6452 dnotify_req->Pid = pSMB->hdr.Pid;
6453 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6454 dnotify_req->Mid = pSMB->hdr.Mid;
6455 dnotify_req->Tid = pSMB->hdr.Tid;
6456 dnotify_req->Uid = pSMB->hdr.Uid;
6457 dnotify_req->netfid = netfid;
6458 dnotify_req->pfile = pfile;
6459 dnotify_req->filter = filter;
6460 dnotify_req->multishot = multishot;
6461 spin_lock(&GlobalMid_Lock);
6462 list_add_tail(&dnotify_req->lhead,
6463 &GlobalDnotifyReqList);
6464 spin_unlock(&GlobalMid_Lock);
6465 } else
6466 rc = -ENOMEM;
6467 }
6468 cifs_buf_release(pSMB);
6469 return rc;
6470}
6471#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */