blob: 741b83c59a30626ed7c148ba2baa8769ea6be4fb [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 Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500101 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Steve French3afca262016-09-22 18:58:16 -0500107 spin_unlock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500142 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara2c4f6b72018-07-05 13:46:34 -0300153 rc = wait_event_interruptible_timeout(server->response_q,
154 (server->tcpStatus != CifsNeedReconnect),
155 10 * HZ);
156 if (rc < 0) {
157 cifs_dbg(FYI, "%s: aborting reconnect due to a received"
158 " signal by the process\n", __func__);
159 return -ERESTARTSYS;
160 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400161
Steve Frenchfd88ce92011-04-12 01:01:14 +0000162 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400163 if (server->tcpStatus != CifsNeedReconnect)
164 break;
165
166 /*
167 * on "soft" mounts we wait once. Hard mounts keep
168 * retrying until process is killed or server comes
169 * back on-line
170 */
Jeff Laytond4025392011-02-07 08:54:35 -0500171 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500172 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400173 return -EHOSTDOWN;
174 }
175 }
176
177 if (!ses->need_reconnect && !tcon->need_reconnect)
178 return 0;
179
180 nls_codepage = load_nls_default();
181
182 /*
183 * need to prevent multiple threads trying to simultaneously
184 * reconnect the same SMB session
185 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000186 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400187 rc = cifs_negotiate_protocol(0, ses);
188 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400189 rc = cifs_setup_session(0, ses, nls_codepage);
190
191 /* do we need to reconnect tcon? */
192 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400194 goto out;
195 }
196
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400197 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400198 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000199 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500200 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400201
202 if (rc)
203 goto out;
204
Jeff Layton9162ab22009-09-03 12:07:17 -0400205 atomic_inc(&tconInfoReconnectCount);
206
207 /* tell server Unix caps we support */
208 if (ses->capabilities & CAP_UNIX)
209 reset_cifs_unix_caps(0, tcon, NULL, NULL);
210
211 /*
212 * Removed call to reopen open files here. It is safer (and faster) to
213 * reopen files one at a time as needed in read and write.
214 *
215 * FIXME: what about file locks? don't we need to reclaim them ASAP?
216 */
217
218out:
219 /*
220 * Check if handle based operation so we know whether we can continue
221 * or not without returning to caller to reset file handle
222 */
223 switch (smb_command) {
224 case SMB_COM_READ_ANDX:
225 case SMB_COM_WRITE_ANDX:
226 case SMB_COM_CLOSE:
227 case SMB_COM_FIND_CLOSE2:
228 case SMB_COM_LOCKING_ANDX:
229 rc = -EAGAIN;
230 }
231
232 unload_nls(nls_codepage);
233 return rc;
234}
235
Steve Frenchad7a2922008-02-07 23:25:02 +0000236/* Allocate and return pointer to an SMB request buffer, and set basic
237 SMB information in the SMB header. If the return code is zero, this
238 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239static int
Steve French96daf2b2011-05-27 04:34:02 +0000240small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000241 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
Jeff Laytonf5695992010-09-29 15:27:08 -0400243 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Jeff Layton9162ab22009-09-03 12:07:17 -0400245 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000246 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 return rc;
248
249 *request_buf = cifs_small_buf_get();
250 if (*request_buf == NULL) {
251 /* BB should we add a retry in here if not a writepage? */
252 return -ENOMEM;
253 }
254
Steve French63135e02007-07-17 17:34:02 +0000255 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000256 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Steve French790fe572007-07-07 19:25:05 +0000258 if (tcon != NULL)
259 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700260
Jeff Laytonf5695992010-09-29 15:27:08 -0400261 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000262}
263
Steve French12b3b8f2006-02-09 21:12:47 +0000264int
Steve French50c2f752007-07-13 00:33:32 +0000265small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000266 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000267{
268 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000269 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000270
Steve French5815449d2006-02-14 01:36:20 +0000271 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000272 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000273 return rc;
274
Steve French04fdabe2006-02-10 05:52:50 +0000275 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400276 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000277 if (ses->capabilities & CAP_UNICODE)
278 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000279 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000280 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
281
282 /* uid, tid can stay at zero as set in header assemble */
283
Steve French50c2f752007-07-13 00:33:32 +0000284 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000285 this function is used after 1st of session setup requests */
286
287 return rc;
288}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290/* If the return code is zero, this function must fill in request_buf pointer */
291static int
Steve French96daf2b2011-05-27 04:34:02 +0000292__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400293 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 *request_buf = cifs_buf_get();
296 if (*request_buf == NULL) {
297 /* BB should we add a retry in here if not a writepage? */
298 return -ENOMEM;
299 }
300 /* Although the original thought was we needed the response buf for */
301 /* potential retries of smb operations it turns out we can determine */
302 /* from the mid flags when the request buffer can be resent without */
303 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000304 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000305 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000308 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Steve French790fe572007-07-07 19:25:05 +0000310 if (tcon != NULL)
311 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700312
Jeff Laytonf5695992010-09-29 15:27:08 -0400313 return 0;
314}
315
316/* If the return code is zero, this function must fill in request_buf pointer */
317static int
Steve French96daf2b2011-05-27 04:34:02 +0000318smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400319 void **request_buf, void **response_buf)
320{
321 int rc;
322
323 rc = cifs_reconnect_tcon(tcon, smb_command);
324 if (rc)
325 return rc;
326
327 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
328}
329
330static int
Steve French96daf2b2011-05-27 04:34:02 +0000331smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400332 void **request_buf, void **response_buf)
333{
334 if (tcon->ses->need_reconnect || tcon->need_reconnect)
335 return -EHOSTDOWN;
336
337 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338}
339
Steve French50c2f752007-07-13 00:33:32 +0000340static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Jeff Layton12df83c2011-01-20 13:36:51 -0500344 /* check for plausible wct */
345 if (pSMB->hdr.WordCount < 10)
346 goto vt2_err;
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500349 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
350 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
351 goto vt2_err;
352
Jeff Layton12df83c2011-01-20 13:36:51 -0500353 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
354 if (total_size >= 512)
355 goto vt2_err;
356
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400357 /* check that bcc is at least as big as parms + data, and that it is
358 * less than negotiated smb buffer
359 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500360 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
361 if (total_size > get_bcc(&pSMB->hdr) ||
362 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
363 goto vt2_err;
364
365 return 0;
366vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000367 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500369 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
Jeff Layton690c5222011-01-20 13:36:51 -0500371
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400372static int
Jeff Layton3f618222013-06-12 19:52:14 -0500373decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400374{
375 int rc = 0;
376 u16 count;
377 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500378 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400379
380 count = get_bcc(&pSMBr->hdr);
381 if (count < SMB1_CLIENT_GUID_SIZE)
382 return -EIO;
383
384 spin_lock(&cifs_tcp_ses_lock);
385 if (server->srv_count > 1) {
386 spin_unlock(&cifs_tcp_ses_lock);
387 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
388 cifs_dbg(FYI, "server UID changed\n");
389 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
390 }
391 } else {
392 spin_unlock(&cifs_tcp_ses_lock);
393 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
394 }
395
396 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500397 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400398 } else {
399 count -= SMB1_CLIENT_GUID_SIZE;
400 rc = decode_negTokenInit(
401 pSMBr->u.extended_response.SecurityBlob, count, server);
402 if (rc != 1)
403 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400404 }
405
406 return 0;
407}
408
Jeff Layton9ddec562013-05-26 07:00:58 -0400409int
Jeff Layton38d77c52013-05-26 07:01:00 -0400410cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400411{
Jeff Layton50285882013-06-27 12:45:00 -0400412 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
413 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400414 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
415
416 /*
417 * Is signing required by mnt options? If not then check
418 * global_secflags to see if it is there.
419 */
420 if (!mnt_sign_required)
421 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
422 CIFSSEC_MUST_SIGN);
423
424 /*
425 * If signing is required then it's automatically enabled too,
426 * otherwise, check to see if the secflags allow it.
427 */
428 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
429 (global_secflags & CIFSSEC_MAY_SIGN);
430
431 /* If server requires signing, does client allow it? */
432 if (srv_sign_required) {
433 if (!mnt_sign_enabled) {
434 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
435 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400436 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400437 server->sign = true;
438 }
439
440 /* If client requires signing, does server allow it? */
441 if (mnt_sign_required) {
442 if (!srv_sign_enabled) {
443 cifs_dbg(VFS, "Server does not support signing!");
444 return -ENOTSUPP;
445 }
446 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400447 }
448
449 return 0;
450}
451
Jeff Layton2190eca2013-05-26 07:00:57 -0400452#ifdef CONFIG_CIFS_WEAK_PW_HASH
453static int
Jeff Layton3f618222013-06-12 19:52:14 -0500454decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400455{
456 __s16 tmp;
457 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
458
459 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
460 return -EOPNOTSUPP;
461
Jeff Layton2190eca2013-05-26 07:00:57 -0400462 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
463 server->maxReq = min_t(unsigned int,
464 le16_to_cpu(rsp->MaxMpxCount),
465 cifs_max_pending);
466 set_credits(server, server->maxReq);
467 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400468 /* even though we do not use raw we might as well set this
469 accurately, in case we ever find a need for it */
470 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
471 server->max_rw = 0xFF00;
472 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
473 } else {
474 server->max_rw = 0;/* do not need to use raw anyway */
475 server->capabilities = CAP_MPX_MODE;
476 }
477 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
478 if (tmp == -1) {
479 /* OS/2 often does not set timezone therefore
480 * we must use server time to calc time zone.
481 * Could deviate slightly from the right zone.
482 * Smallest defined timezone difference is 15 minutes
483 * (i.e. Nepal). Rounding up/down is done to match
484 * this requirement.
485 */
486 int val, seconds, remain, result;
487 struct timespec ts, utc;
488 utc = CURRENT_TIME;
489 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
490 rsp->SrvTime.Time, 0);
491 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
492 (int)ts.tv_sec, (int)utc.tv_sec,
493 (int)(utc.tv_sec - ts.tv_sec));
494 val = (int)(utc.tv_sec - ts.tv_sec);
495 seconds = abs(val);
496 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
497 remain = seconds % MIN_TZ_ADJ;
498 if (remain >= (MIN_TZ_ADJ / 2))
499 result += MIN_TZ_ADJ;
500 if (val < 0)
501 result = -result;
502 server->timeAdj = result;
503 } else {
504 server->timeAdj = (int)tmp;
505 server->timeAdj *= 60; /* also in seconds */
506 }
507 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
508
509
510 /* BB get server time for time conversions and add
511 code to use it and timezone since this is not UTC */
512
513 if (rsp->EncryptionKeyLength ==
514 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
515 memcpy(server->cryptkey, rsp->EncryptionKey,
516 CIFS_CRYPTO_KEY_SIZE);
517 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
518 return -EIO; /* need cryptkey unless plain text */
519 }
520
521 cifs_dbg(FYI, "LANMAN negotiated\n");
522 return 0;
523}
524#else
525static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500526decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400527{
528 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
529 return -EOPNOTSUPP;
530}
531#endif
532
Jeff Layton91934002013-05-26 07:00:58 -0400533static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500534should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400535{
Jeff Layton3f618222013-06-12 19:52:14 -0500536 switch (sectype) {
537 case RawNTLMSSP:
538 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400539 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500540 case Unspecified:
541 if (global_secflags &
542 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
543 return true;
544 /* Fallthrough */
545 default:
546 return false;
547 }
Jeff Layton91934002013-05-26 07:00:58 -0400548}
549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400551CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 NEGOTIATE_REQ *pSMB;
554 NEGOTIATE_RSP *pSMBr;
555 int rc = 0;
556 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000557 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400558 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 u16 count;
560
Jeff Layton3534b852013-05-24 07:41:01 -0400561 if (!server) {
562 WARN(1, "%s: server is NULL!\n", __func__);
563 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 }
Jeff Layton3534b852013-05-24 07:41:01 -0400565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
567 (void **) &pSMB, (void **) &pSMBr);
568 if (rc)
569 return rc;
Steve French750d1152006-06-27 06:28:30 +0000570
Pavel Shilovsky88257362012-05-23 14:01:59 +0400571 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000572 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000573
Jeff Layton3f618222013-06-12 19:52:14 -0500574 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400575 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000576 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
577 }
Steve French50c2f752007-07-13 00:33:32 +0000578
Steve French39798772006-05-31 22:40:51 +0000579 count = 0;
Stephen Rothwell7a0ee612018-09-03 13:15:58 +1000580 /*
581 * We know that all the name entries in the protocols array
582 * are short (< 16 bytes anyway) and are NUL terminated.
583 */
Steve French50c2f752007-07-13 00:33:32 +0000584 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwell7a0ee612018-09-03 13:15:58 +1000585 size_t len = strlen(protocols[i].name) + 1;
586
587 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
588 count += len;
Steve French39798772006-05-31 22:40:51 +0000589 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000590 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 pSMB->ByteCount = cpu_to_le16(count);
592
593 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
594 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000595 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000596 goto neg_err_exit;
597
Jeff Layton9bf67e52010-04-24 07:57:46 -0400598 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500599 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000600 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400601 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000602 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000603 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000604 could not negotiate a common dialect */
605 rc = -EOPNOTSUPP;
606 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000607 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400608 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500609 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400610 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000611 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000612 /* unknown wct */
613 rc = -EOPNOTSUPP;
614 goto neg_err_exit;
615 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400616 /* else wct == 17, NTLM or better */
617
Steve French96daf2b2011-05-27 04:34:02 +0000618 server->sec_mode = pSMBr->SecurityMode;
619 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500620 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000621
Steve French254e55e2006-06-04 05:53:15 +0000622 /* one byte, so no need to convert this or EncryptionKeyLen from
623 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300624 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
625 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400626 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000627 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400628 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000629 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500630 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000631 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000632 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
633 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400634
Jeff Laytone598d1d82013-05-26 07:00:59 -0400635 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
636 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500637 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000638 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100639 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
640 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400641 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500642 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400643 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000644 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400645 } else {
646 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000647 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400648 }
Steve French254e55e2006-06-04 05:53:15 +0000649
650signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400651 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400652 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000653neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700654 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000655
Joe Perchesf96637b2013-05-04 22:12:25 -0500656 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 return rc;
658}
659
660int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400661CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
663 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Joe Perchesf96637b2013-05-04 22:12:25 -0500666 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500667
668 /* BB: do we need to check this? These should never be NULL. */
669 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
670 return -EIO;
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500673 * No need to return error on this operation if tid invalidated and
674 * closed on server already e.g. due to tcp session crashing. Also,
675 * the tcon is no longer on the list, so no need to take lock before
676 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 */
Steve French268875b2009-06-25 00:29:21 +0000678 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000679 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Steve French50c2f752007-07-13 00:33:32 +0000681 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700682 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500683 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return rc;
Steve French133672e2007-11-13 22:41:37 +0000685
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400686 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500688 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Steve French50c2f752007-07-13 00:33:32 +0000690 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 if (rc == -EAGAIN)
693 rc = 0;
694
695 return rc;
696}
697
Jeff Layton766fdbb2011-01-11 07:24:21 -0500698/*
699 * This is a no-op for now. We're not really interested in the reply, but
700 * rather in the fact that the server sent one and that server->lstrp
701 * gets updated.
702 *
703 * FIXME: maybe we should consider checking that the reply matches request?
704 */
705static void
706cifs_echo_callback(struct mid_q_entry *mid)
707{
708 struct TCP_Server_Info *server = mid->callback_data;
709
Christopher Oo5fb4e282015-06-25 16:10:48 -0700710 mutex_lock(&server->srv_mutex);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500711 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -0700712 mutex_unlock(&server->srv_mutex);
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;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400721 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700722 struct smb_rqst rqst = { .rq_iov = &iov,
723 .rq_nvec = 1 };
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 French2ac2ad92017-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 Layton99d86c82011-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);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400741 iov.iov_base = smb;
742 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500743
Jeff Laytonfec344e2012-09-18 16:20:35 -0700744 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400745 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500747 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748
749 cifs_small_buf_release(smb);
750
751 return rc;
752}
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400755CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 LOGOFF_ANDX_REQ *pSMB;
758 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Joe Perchesf96637b2013-05-04 22:12:25 -0500760 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500761
762 /*
763 * BB: do we need to check validity of ses and server? They should
764 * always be valid since we have an active reference. If not, that
765 * should probably be a BUG()
766 */
767 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return -EIO;
769
Steve Frenchd7b619c2010-02-25 05:36:46 +0000770 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000771 if (ses->need_reconnect)
772 goto session_already_dead; /* no need to send SMBlogoff if uid
773 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
775 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000776 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return rc;
778 }
779
Pavel Shilovsky88257362012-05-23 14:01:59 +0400780 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700781
Jeff Layton38d77c52013-05-26 07:01:00 -0400782 if (ses->server->sign)
783 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 pSMB->hdr.Uid = ses->Suid;
786
787 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400788 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000789session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000790 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000793 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 error */
795 if (rc == -EAGAIN)
796 rc = 0;
797 return rc;
798}
799
800int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400801CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
802 const char *fileName, __u16 type,
803 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000804{
805 TRANSACTION2_SPI_REQ *pSMB = NULL;
806 TRANSACTION2_SPI_RSP *pSMBr = NULL;
807 struct unlink_psx_rq *pRqD;
808 int name_len;
809 int rc = 0;
810 int bytes_returned = 0;
811 __u16 params, param_offset, offset, byte_count;
812
Joe Perchesf96637b2013-05-04 22:12:25 -0500813 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000814PsxDelete:
815 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
816 (void **) &pSMBr);
817 if (rc)
818 return rc;
819
820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
821 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600822 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
823 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000824 name_len++; /* trailing null */
825 name_len *= 2;
826 } else { /* BB add path length overrun check */
827 name_len = strnlen(fileName, PATH_MAX);
828 name_len++; /* trailing null */
829 strncpy(pSMB->FileName, fileName, name_len);
830 }
831
832 params = 6 + name_len;
833 pSMB->MaxParameterCount = cpu_to_le16(2);
834 pSMB->MaxDataCount = 0; /* BB double check this with jra */
835 pSMB->MaxSetupCount = 0;
836 pSMB->Reserved = 0;
837 pSMB->Flags = 0;
838 pSMB->Timeout = 0;
839 pSMB->Reserved2 = 0;
840 param_offset = offsetof(struct smb_com_transaction2_spi_req,
841 InformationLevel) - 4;
842 offset = param_offset + params;
843
844 /* Setup pointer to Request Data (inode type) */
845 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
846 pRqD->type = cpu_to_le16(type);
847 pSMB->ParameterOffset = cpu_to_le16(param_offset);
848 pSMB->DataOffset = cpu_to_le16(offset);
849 pSMB->SetupCount = 1;
850 pSMB->Reserved3 = 0;
851 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
852 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
853
854 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
855 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
856 pSMB->ParameterCount = cpu_to_le16(params);
857 pSMB->TotalParameterCount = pSMB->ParameterCount;
858 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
859 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000860 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000861 pSMB->ByteCount = cpu_to_le16(byte_count);
862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000864 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500865 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000866 cifs_buf_release(pSMB);
867
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400868 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000869
870 if (rc == -EAGAIN)
871 goto PsxDelete;
872
873 return rc;
874}
875
876int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700877CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
878 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
880 DELETE_FILE_REQ *pSMB = NULL;
881 DELETE_FILE_RSP *pSMBr = NULL;
882 int rc = 0;
883 int bytes_returned;
884 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500885 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887DelFileRetry:
888 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
889 (void **) &pSMBr);
890 if (rc)
891 return rc;
892
893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700894 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
895 PATH_MAX, cifs_sb->local_nls,
896 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 name_len++; /* trailing null */
898 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700899 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700900 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700902 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
904 pSMB->SearchAttributes =
905 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
906 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000907 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 pSMB->ByteCount = cpu_to_le16(name_len + 1);
909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400911 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000912 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500913 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 cifs_buf_release(pSMB);
916 if (rc == -EAGAIN)
917 goto DelFileRetry;
918
919 return rc;
920}
921
922int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400923CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
924 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
926 DELETE_DIRECTORY_REQ *pSMB = NULL;
927 DELETE_DIRECTORY_RSP *pSMBr = NULL;
928 int rc = 0;
929 int bytes_returned;
930 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500931 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Joe Perchesf96637b2013-05-04 22:12:25 -0500933 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934RmDirRetry:
935 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
936 (void **) &pSMBr);
937 if (rc)
938 return rc;
939
940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400941 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
942 PATH_MAX, cifs_sb->local_nls,
943 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 name_len++; /* trailing null */
945 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700946 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400947 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400949 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 }
951
952 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000953 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 pSMB->ByteCount = cpu_to_le16(name_len + 1);
955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400957 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000958 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500959 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 cifs_buf_release(pSMB);
962 if (rc == -EAGAIN)
963 goto RmDirRetry;
964 return rc;
965}
966
967int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300968CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
969 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
971 int rc = 0;
972 CREATE_DIRECTORY_REQ *pSMB = NULL;
973 CREATE_DIRECTORY_RSP *pSMBr = NULL;
974 int bytes_returned;
975 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500976 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Joe Perchesf96637b2013-05-04 22:12:25 -0500978 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979MkDirRetry:
980 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
981 (void **) &pSMBr);
982 if (rc)
983 return rc;
984
985 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600986 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300987 PATH_MAX, cifs_sb->local_nls,
988 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name_len++; /* trailing null */
990 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700991 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 name_len = strnlen(name, PATH_MAX);
993 name_len++; /* trailing null */
994 strncpy(pSMB->DirName, name, name_len);
995 }
996
997 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000998 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1000 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1001 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001002 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001003 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001004 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 cifs_buf_release(pSMB);
1007 if (rc == -EAGAIN)
1008 goto MkDirRetry;
1009 return rc;
1010}
1011
Steve French2dd29d32007-04-23 22:07:35 +00001012int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001013CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1014 __u32 posix_flags, __u64 mode, __u16 *netfid,
1015 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1016 const char *name, const struct nls_table *nls_codepage,
1017 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001018{
1019 TRANSACTION2_SPI_REQ *pSMB = NULL;
1020 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1021 int name_len;
1022 int rc = 0;
1023 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001024 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001025 OPEN_PSX_REQ *pdata;
1026 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001027
Joe Perchesf96637b2013-05-04 22:12:25 -05001028 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001029PsxCreat:
1030 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1031 (void **) &pSMBr);
1032 if (rc)
1033 return rc;
1034
1035 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1036 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001037 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1038 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001039 name_len++; /* trailing null */
1040 name_len *= 2;
1041 } else { /* BB improve the check for buffer overruns BB */
1042 name_len = strnlen(name, PATH_MAX);
1043 name_len++; /* trailing null */
1044 strncpy(pSMB->FileName, name, name_len);
1045 }
1046
1047 params = 6 + name_len;
1048 count = sizeof(OPEN_PSX_REQ);
1049 pSMB->MaxParameterCount = cpu_to_le16(2);
1050 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1051 pSMB->MaxSetupCount = 0;
1052 pSMB->Reserved = 0;
1053 pSMB->Flags = 0;
1054 pSMB->Timeout = 0;
1055 pSMB->Reserved2 = 0;
1056 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001057 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001058 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001059 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001060 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001061 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001062 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001063 pdata->OpenFlags = cpu_to_le32(*pOplock);
1064 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1065 pSMB->DataOffset = cpu_to_le16(offset);
1066 pSMB->SetupCount = 1;
1067 pSMB->Reserved3 = 0;
1068 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1069 byte_count = 3 /* pad */ + params + count;
1070
1071 pSMB->DataCount = cpu_to_le16(count);
1072 pSMB->ParameterCount = cpu_to_le16(params);
1073 pSMB->TotalDataCount = pSMB->DataCount;
1074 pSMB->TotalParameterCount = pSMB->ParameterCount;
1075 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1076 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001077 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001078 pSMB->ByteCount = cpu_to_le16(byte_count);
1079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1081 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001082 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001083 goto psx_create_err;
1084 }
1085
Joe Perchesf96637b2013-05-04 22:12:25 -05001086 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001087 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1088
Jeff Layton820a8032011-05-04 08:05:26 -04001089 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001090 rc = -EIO; /* bad smb */
1091 goto psx_create_err;
1092 }
1093
1094 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001095 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001096 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001097
Steve French2dd29d32007-04-23 22:07:35 +00001098 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001099 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001100 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1101 /* Let caller know file was created so we can set the mode. */
1102 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001103 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001104 *pOplock |= CIFS_CREATE_ACTION;
1105 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001106 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1107 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001108 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001109 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001110 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001111 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001112 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001113 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001114 goto psx_create_err;
1115 }
Steve French50c2f752007-07-13 00:33:32 +00001116 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001117 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001118 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001119 }
Steve French2dd29d32007-04-23 22:07:35 +00001120
1121psx_create_err:
1122 cifs_buf_release(pSMB);
1123
Steve French65bc98b2009-07-10 15:27:25 +00001124 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001125 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001126 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001127 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001128
1129 if (rc == -EAGAIN)
1130 goto PsxCreat;
1131
Steve French50c2f752007-07-13 00:33:32 +00001132 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001133}
1134
Steve Frencha9d02ad2005-08-24 23:06:05 -07001135static __u16 convert_disposition(int disposition)
1136{
1137 __u16 ofun = 0;
1138
1139 switch (disposition) {
1140 case FILE_SUPERSEDE:
1141 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1142 break;
1143 case FILE_OPEN:
1144 ofun = SMBOPEN_OAPPEND;
1145 break;
1146 case FILE_CREATE:
1147 ofun = SMBOPEN_OCREATE;
1148 break;
1149 case FILE_OPEN_IF:
1150 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1151 break;
1152 case FILE_OVERWRITE:
1153 ofun = SMBOPEN_OTRUNC;
1154 break;
1155 case FILE_OVERWRITE_IF:
1156 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1157 break;
1158 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001159 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001160 ofun = SMBOPEN_OAPPEND; /* regular open */
1161 }
1162 return ofun;
1163}
1164
Jeff Layton35fc37d2008-05-14 10:22:03 -07001165static int
1166access_flags_to_smbopen_mode(const int access_flags)
1167{
1168 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1169
1170 if (masked_flags == GENERIC_READ)
1171 return SMBOPEN_READ;
1172 else if (masked_flags == GENERIC_WRITE)
1173 return SMBOPEN_WRITE;
1174
1175 /* just go for read/write */
1176 return SMBOPEN_READWRITE;
1177}
1178
Steve Frencha9d02ad2005-08-24 23:06:05 -07001179int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001180SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001182 const int access_flags, const int create_options, __u16 *netfid,
1183 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001184 const struct nls_table *nls_codepage, int remap)
1185{
1186 int rc = -EACCES;
1187 OPENX_REQ *pSMB = NULL;
1188 OPENX_RSP *pSMBr = NULL;
1189 int bytes_returned;
1190 int name_len;
1191 __u16 count;
1192
1193OldOpenRetry:
1194 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1195 (void **) &pSMBr);
1196 if (rc)
1197 return rc;
1198
1199 pSMB->AndXCommand = 0xFF; /* none */
1200
1201 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1202 count = 1; /* account for one byte pad to word boundary */
1203 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001204 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1205 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 name_len++; /* trailing null */
1207 name_len *= 2;
1208 } else { /* BB improve check for buffer overruns BB */
1209 count = 0; /* no pad */
1210 name_len = strnlen(fileName, PATH_MAX);
1211 name_len++; /* trailing null */
1212 strncpy(pSMB->fileName, fileName, name_len);
1213 }
1214 if (*pOplock & REQ_OPLOCK)
1215 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001216 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001217 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001218
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001220 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1222 /* set file as system file if special file such
1223 as fifo and server expecting SFU style and
1224 no Unix extensions */
1225
Steve French790fe572007-07-07 19:25:05 +00001226 if (create_options & CREATE_OPTION_SPECIAL)
1227 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001228 else /* BB FIXME BB */
1229 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230
Jeff Layton67750fb2008-05-09 22:28:02 +00001231 if (create_options & CREATE_OPTION_READONLY)
1232 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233
1234 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001235/* pSMB->CreateOptions = cpu_to_le32(create_options &
1236 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001238
1239 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001240 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001242 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243
1244 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001246 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001247 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001249 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 } else {
1251 /* BB verify if wct == 15 */
1252
Steve French582d21e2008-05-13 04:54:12 +00001253/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001259/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1262
Steve French790fe572007-07-07 19:25:05 +00001263 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001275 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 }
1277 }
1278
1279 cifs_buf_release(pSMB);
1280 if (rc == -EAGAIN)
1281 goto OldOpenRetry;
1282 return rc;
1283}
1284
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001286CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1287 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288{
1289 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001290 OPEN_REQ *req = NULL;
1291 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 int bytes_returned;
1293 int name_len;
1294 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001295 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1296 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001297 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001298 const struct nls_table *nls = cifs_sb->local_nls;
1299 int create_options = oparms->create_options;
1300 int desired_access = oparms->desired_access;
1301 int disposition = oparms->disposition;
1302 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
1304openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001305 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1306 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (rc)
1308 return rc;
1309
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001310 /* no commands go after this */
1311 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001313 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1314 /* account for one byte pad to word boundary */
1315 count = 1;
1316 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1317 path, PATH_MAX, nls, remap);
1318 /* trailing null */
1319 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001321 req->NameLength = cpu_to_le16(name_len);
1322 } else {
1323 /* BB improve check for buffer overruns BB */
1324 /* no pad */
1325 count = 0;
1326 name_len = strnlen(path, PATH_MAX);
1327 /* trailing null */
1328 name_len++;
1329 req->NameLength = cpu_to_le16(name_len);
1330 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001332
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001333 if (*oplock & REQ_OPLOCK)
1334 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1335 else if (*oplock & REQ_BATCHOPLOCK)
1336 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1337
1338 req->DesiredAccess = cpu_to_le32(desired_access);
1339 req->AllocationSize = 0;
1340
1341 /*
1342 * Set file as system file if special file such as fifo and server
1343 * expecting SFU style and no Unix extensions.
1344 */
1345 if (create_options & CREATE_OPTION_SPECIAL)
1346 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1347 else
1348 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1349
1350 /*
1351 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1352 * sensitive checks for other servers such as Samba.
1353 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001355 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Jeff Layton67750fb2008-05-09 22:28:02 +00001357 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001358 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001359
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001360 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1361 req->CreateDisposition = cpu_to_le32(disposition);
1362 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1363
Steve French09d1db52005-04-28 22:41:08 -07001364 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001365 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1366 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001369 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001371 req->ByteCount = cpu_to_le16(count);
1372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1373 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001374 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001376 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001377 cifs_buf_release(req);
1378 if (rc == -EAGAIN)
1379 goto openRetry;
1380 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001382
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001383 /* 1 byte no need to le_to_cpu */
1384 *oplock = rsp->OplockLevel;
1385 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001386 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001387
1388 /* Let caller know file was created so we can set the mode. */
1389 /* Do we care about the CreateAction in any other cases? */
1390 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1391 *oplock |= CIFS_CREATE_ACTION;
1392
1393 if (buf) {
1394 /* copy from CreationTime to Attributes */
1395 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1396 /* the file_info buf is endian converted by caller */
1397 buf->AllocationSize = rsp->AllocationSize;
1398 buf->EndOfFile = rsp->EndOfFile;
1399 buf->NumberOfLinks = cpu_to_le32(1);
1400 buf->DeletePending = 0;
1401 }
1402
1403 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 return rc;
1405}
1406
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001407/*
1408 * Discard any remaining data in the current SMB. To do this, we borrow the
1409 * current bigbuf.
1410 */
1411static int
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001412discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001413{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001414 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001415 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001416
1417 while (remaining > 0) {
1418 int length;
1419
1420 length = cifs_read_from_socket(server, server->bigbuf,
1421 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001422 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001423 if (length < 0)
1424 return length;
1425 server->total_read += length;
1426 remaining -= length;
1427 }
1428
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429 return 0;
1430}
1431
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001432static int
1433cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1434{
1435 int length;
1436 struct cifs_readdata *rdata = mid->callback_data;
1437
1438 length = discard_remaining_data(server);
1439 dequeue_mid(mid, rdata->result);
Sachin Prabhud8fd99d2017-03-03 15:41:38 -08001440 mid->resp_buf = server->smallbuf;
1441 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001442 return length;
1443}
1444
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001445int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1447{
1448 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001449 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001451 char *buf = server->smallbuf;
1452 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453
Joe Perchesf96637b2013-05-04 22:12:25 -05001454 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1455 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001456
1457 /*
1458 * read the rest of READ_RSP header (sans Data array), or whatever we
1459 * can if there's not enough data. At this point, we've read down to
1460 * the Mid.
1461 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001462 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001463 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001464
Al Viroa6137302016-01-09 19:37:16 -05001465 length = cifs_read_from_socket(server,
1466 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001467 if (length < 0)
1468 return length;
1469 server->total_read += length;
1470
Pavel Shilovsky92d7d3e2017-07-08 14:32:00 -07001471 if (server->ops->is_session_expired &&
1472 server->ops->is_session_expired(buf)) {
1473 cifs_reconnect(server);
1474 wake_up(&server->response_q);
1475 return -1;
1476 }
1477
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001478 if (server->ops->is_status_pending &&
1479 server->ops->is_status_pending(buf, server, 0)) {
1480 discard_remaining_data(server);
1481 return -1;
1482 }
1483
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001484 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001485 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001486 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001487 cifs_dbg(FYI, "%s: server returned error %d\n",
1488 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 return cifs_readv_discard(server, mid);
1490 }
1491
1492 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001493 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001494 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1495 __func__, server->total_read,
1496 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001497 rdata->result = -EIO;
1498 return cifs_readv_discard(server, mid);
1499 }
1500
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001501 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001502 if (data_offset < server->total_read) {
1503 /*
1504 * win2k8 sometimes sends an offset of 0 when the read
1505 * is beyond the EOF. Treat it as if the data starts just after
1506 * the header.
1507 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001508 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1509 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001510 data_offset = server->total_read;
1511 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1512 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001513 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1514 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001515 rdata->result = -EIO;
1516 return cifs_readv_discard(server, mid);
1517 }
1518
Joe Perchesf96637b2013-05-04 22:12:25 -05001519 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1520 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001521
1522 len = data_offset - server->total_read;
1523 if (len > 0) {
1524 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001525 length = cifs_read_from_socket(server,
1526 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001527 if (length < 0)
1528 return length;
1529 server->total_read += length;
1530 }
1531
1532 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001533 rdata->iov.iov_base = buf;
1534 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001535 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1536 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001537
1538 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001539 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001540 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541 /* data_len is corrupt -- discard frame */
1542 rdata->result = -EIO;
1543 return cifs_readv_discard(server, mid);
1544 }
1545
Jeff Layton8321fec2012-09-19 06:22:32 -07001546 length = rdata->read_into_pages(server, rdata, data_len);
1547 if (length < 0)
1548 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549
Jeff Layton8321fec2012-09-19 06:22:32 -07001550 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001551
Joe Perchesf96637b2013-05-04 22:12:25 -05001552 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1553 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001554
1555 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001556 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557 return cifs_readv_discard(server, mid);
1558
1559 dequeue_mid(mid, false);
Sachin Prabhud8fd99d2017-03-03 15:41:38 -08001560 mid->resp_buf = server->smallbuf;
1561 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001562 return length;
1563}
1564
1565static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001566cifs_readv_callback(struct mid_q_entry *mid)
1567{
1568 struct cifs_readdata *rdata = mid->callback_data;
1569 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1570 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001571 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1572 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001573 .rq_pages = rdata->pages,
1574 .rq_npages = rdata->nr_pages,
1575 .rq_pagesz = rdata->pagesz,
1576 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577
Joe Perchesf96637b2013-05-04 22:12:25 -05001578 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1579 __func__, mid->mid, mid->mid_state, rdata->result,
1580 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001581
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001582 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001583 case MID_RESPONSE_RECEIVED:
1584 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001585 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001586 int rc = 0;
1587
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001588 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001589 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001590 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001591 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1592 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001593 }
1594 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001595 task_io_account_read(rdata->got_bytes);
1596 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001597 break;
1598 case MID_REQUEST_SUBMITTED:
1599 case MID_RETRY_NEEDED:
1600 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001601 if (server->sign && rdata->got_bytes)
1602 /* reset bytes number since we can not check a sign */
1603 rdata->got_bytes = 0;
1604 /* FIXME: should this be counted toward the initiating task? */
1605 task_io_account_read(rdata->got_bytes);
1606 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001607 break;
1608 default:
1609 rdata->result = -EIO;
1610 }
1611
Jeff Laytonda472fc2012-03-23 14:40:53 -04001612 queue_work(cifsiod_wq, &rdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001613 mutex_lock(&server->srv_mutex);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001614 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001615 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001616 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001617}
1618
1619/* cifs_async_readv - send an async write, and set up mid to handle result */
1620int
1621cifs_async_readv(struct cifs_readdata *rdata)
1622{
1623 int rc;
1624 READ_REQ *smb = NULL;
1625 int wct;
1626 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001627 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001628 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001629
Joe Perchesf96637b2013-05-04 22:12:25 -05001630 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1631 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001632
1633 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1634 wct = 12;
1635 else {
1636 wct = 10; /* old style read */
1637 if ((rdata->offset >> 32) > 0) {
1638 /* can not handle this big offset for old */
1639 return -EIO;
1640 }
1641 }
1642
1643 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1644 if (rc)
1645 return rc;
1646
1647 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1648 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1649
1650 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001651 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001652 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1653 if (wct == 12)
1654 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1655 smb->Remaining = 0;
1656 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1657 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1658 if (wct == 12)
1659 smb->ByteCount = 0;
1660 else {
1661 /* old style read */
1662 struct smb_com_readx_req *smbr =
1663 (struct smb_com_readx_req *)smb;
1664 smbr->ByteCount = 0;
1665 }
1666
1667 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001668 rdata->iov.iov_base = smb;
1669 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001670
Jeff Layton6993f742012-05-16 07:13:17 -04001671 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001672 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1673 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001674
1675 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001676 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001677 else
1678 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001679
1680 cifs_small_buf_release(smb);
1681 return rc;
1682}
1683
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001685CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1686 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687{
1688 int rc = -EACCES;
1689 READ_REQ *pSMB = NULL;
1690 READ_RSP *pSMBr = NULL;
1691 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001692 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001693 int resp_buf_type = 0;
1694 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001695 __u32 pid = io_parms->pid;
1696 __u16 netfid = io_parms->netfid;
1697 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001698 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001699 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
Joe Perchesf96637b2013-05-04 22:12:25 -05001701 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001702 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001703 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001704 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001705 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001706 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001707 /* can not handle this big offset for old */
1708 return -EIO;
1709 }
1710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
1712 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001713 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if (rc)
1715 return rc;
1716
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001717 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1718 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1719
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 /* tcon and ses pointer are checked in smb_init */
1721 if (tcon->ses->server == NULL)
1722 return -ECONNABORTED;
1723
Steve Frenchec637e32005-12-12 20:53:18 -08001724 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001726 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001727 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001728 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001729
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 pSMB->Remaining = 0;
1731 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1732 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001733 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001734 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1735 else {
1736 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001737 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001738 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001739 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001740 }
Steve Frenchec637e32005-12-12 20:53:18 -08001741
1742 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001743 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001744 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001745 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001746 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001747 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001749 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 } else {
1751 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1752 data_length = data_length << 16;
1753 data_length += le16_to_cpu(pSMBr->DataLength);
1754 *nbytes = data_length;
1755
1756 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001757 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001759 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001760 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 rc = -EIO;
1762 *nbytes = 0;
1763 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001764 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001765 le16_to_cpu(pSMBr->DataOffset);
1766/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001767 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001768 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001769 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001770 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001771 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 }
1773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Steve French4b8f9302006-02-26 16:41:18 +00001775/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001776 if (*buf) {
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01001777 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001778 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001779 /* return buffer to caller to free */
1780 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001781 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001782 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001783 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001784 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001785 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001786
1787 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 since file handle passed in no longer valid */
1789 return rc;
1790}
1791
Steve Frenchec637e32005-12-12 20:53:18 -08001792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001794CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001795 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796{
1797 int rc = -EACCES;
1798 WRITE_REQ *pSMB = NULL;
1799 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001800 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 __u32 bytes_sent;
1802 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001803 __u32 pid = io_parms->pid;
1804 __u16 netfid = io_parms->netfid;
1805 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001806 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001807 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Steve Frencha24e2d72010-04-03 17:20:21 +00001809 *nbytes = 0;
1810
Joe Perchesf96637b2013-05-04 22:12:25 -05001811 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001812 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001813 return -ECONNABORTED;
1814
Steve French790fe572007-07-07 19:25:05 +00001815 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001816 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001817 else {
Steve French1c955182005-08-30 20:58:07 -07001818 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001819 if ((offset >> 32) > 0) {
1820 /* can not handle big offset for old srv */
1821 return -EIO;
1822 }
1823 }
Steve French1c955182005-08-30 20:58:07 -07001824
1825 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 (void **) &pSMBr);
1827 if (rc)
1828 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001829
1830 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1831 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1832
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 /* tcon and ses pointer are checked in smb_init */
1834 if (tcon->ses->server == NULL)
1835 return -ECONNABORTED;
1836
1837 pSMB->AndXCommand = 0xFF; /* none */
1838 pSMB->Fid = netfid;
1839 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001840 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001841 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 pSMB->Reserved = 0xFFFFFFFF;
1844 pSMB->WriteMode = 0;
1845 pSMB->Remaining = 0;
1846
Steve French50c2f752007-07-13 00:33:32 +00001847 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 can send more if LARGE_WRITE_X capability returned by the server and if
1849 our buffer is big enough or if we convert to iovecs on socket writes
1850 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001851 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1853 } else {
1854 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1855 & ~0xFF;
1856 }
1857
1858 if (bytes_sent > count)
1859 bytes_sent = count;
1860 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001861 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001862 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001863 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001864 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 /* No buffer */
1866 cifs_buf_release(pSMB);
1867 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001868 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001869 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001870 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001871 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001872 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1875 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001876 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001877
Steve French790fe572007-07-07 19:25:05 +00001878 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001879 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001880 else { /* old style write has byte count 4 bytes earlier
1881 so 4 bytes pad */
1882 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001883 (struct smb_com_writex_req *)pSMB;
1884 pSMBW->ByteCount = cpu_to_le16(byte_count);
1885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
1887 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001888 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001889 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001891 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 } else {
1893 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1894 *nbytes = (*nbytes) << 16;
1895 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301896
1897 /*
1898 * Mask off high 16 bits when bytes written as returned by the
1899 * server is greater than bytes requested by the client. Some
1900 * OS/2 servers are known to set incorrect CountHigh values.
1901 */
1902 if (*nbytes > count)
1903 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 }
1905
1906 cifs_buf_release(pSMB);
1907
Steve French50c2f752007-07-13 00:33:32 +00001908 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 since file handle passed in no longer valid */
1910
1911 return rc;
1912}
1913
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001914void
1915cifs_writedata_release(struct kref *refcount)
1916{
1917 struct cifs_writedata *wdata = container_of(refcount,
1918 struct cifs_writedata, refcount);
1919
1920 if (wdata->cfile)
1921 cifsFileInfo_put(wdata->cfile);
1922
1923 kfree(wdata);
1924}
1925
1926/*
1927 * Write failed with a retryable error. Resend the write request. It's also
1928 * possible that the page was redirtied so re-clean the page.
1929 */
1930static void
1931cifs_writev_requeue(struct cifs_writedata *wdata)
1932{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001933 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001934 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001935 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001936 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001937
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001938 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1939 i = 0;
1940 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001941 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001942 struct cifs_writedata *wdata2;
1943 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001944
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001945 wsize = server->ops->wp_retry_size(inode);
1946 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001947 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001948 if (!nr_pages) {
1949 rc = -ENOTSUPP;
1950 break;
1951 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001952 cur_len = nr_pages * PAGE_SIZE;
1953 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001954 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001955 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001956 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001957 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001958 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001959
1960 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1961 if (!wdata2) {
1962 rc = -ENOMEM;
1963 break;
1964 }
1965
1966 for (j = 0; j < nr_pages; j++) {
1967 wdata2->pages[j] = wdata->pages[i + j];
1968 lock_page(wdata2->pages[j]);
1969 clear_page_dirty_for_io(wdata2->pages[j]);
1970 }
1971
1972 wdata2->sync_mode = wdata->sync_mode;
1973 wdata2->nr_pages = nr_pages;
1974 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001975 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001976 wdata2->tailsz = tailsz;
1977 wdata2->bytes = cur_len;
1978
1979 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1980 if (!wdata2->cfile) {
1981 cifs_dbg(VFS, "No writable handles for inode\n");
1982 rc = -EBADF;
1983 break;
1984 }
1985 wdata2->pid = wdata2->cfile->pid;
1986 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1987
1988 for (j = 0; j < nr_pages; j++) {
1989 unlock_page(wdata2->pages[j]);
1990 if (rc != 0 && rc != -EAGAIN) {
1991 SetPageError(wdata2->pages[j]);
1992 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001993 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001994 }
1995 }
1996
1997 if (rc) {
1998 kref_put(&wdata2->refcount, cifs_writedata_release);
1999 if (rc == -EAGAIN)
2000 continue;
2001 break;
2002 }
2003
2004 rest_len -= cur_len;
2005 i += nr_pages;
2006 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002007
2008 mapping_set_error(inode->i_mapping, rc);
2009 kref_put(&wdata->refcount, cifs_writedata_release);
2010}
2011
Jeff Laytonc2e87642012-03-23 14:40:55 -04002012void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002013cifs_writev_complete(struct work_struct *work)
2014{
2015 struct cifs_writedata *wdata = container_of(work,
2016 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002017 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002018 int i = 0;
2019
2020 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002021 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002022 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002023 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002024 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2025 wdata->bytes);
2026 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2027 return cifs_writev_requeue(wdata);
2028
2029 for (i = 0; i < wdata->nr_pages; i++) {
2030 struct page *page = wdata->pages[i];
2031 if (wdata->result == -EAGAIN)
2032 __set_page_dirty_nobuffers(page);
2033 else if (wdata->result < 0)
2034 SetPageError(page);
2035 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002036 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002037 }
2038 if (wdata->result != -EAGAIN)
2039 mapping_set_error(inode->i_mapping, wdata->result);
2040 kref_put(&wdata->refcount, cifs_writedata_release);
2041}
2042
2043struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002044cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002045{
2046 struct cifs_writedata *wdata;
2047
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002048 /* writedata + number of page pointers */
2049 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002050 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002051 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002053 INIT_LIST_HEAD(&wdata->list);
2054 init_completion(&wdata->done);
2055 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002056 }
2057 return wdata;
2058}
2059
2060/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002061 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 * workqueue completion task.
2063 */
2064static void
2065cifs_writev_callback(struct mid_q_entry *mid)
2066{
2067 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002068 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002069 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070 unsigned int written;
2071 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2072
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002073 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002074 case MID_RESPONSE_RECEIVED:
2075 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2076 if (wdata->result != 0)
2077 break;
2078
2079 written = le16_to_cpu(smb->CountHigh);
2080 written <<= 16;
2081 written += le16_to_cpu(smb->Count);
2082 /*
2083 * Mask off high 16 bits when bytes written as returned
2084 * by the server is greater than bytes requested by the
2085 * client. OS/2 servers are known to set incorrect
2086 * CountHigh values.
2087 */
2088 if (written > wdata->bytes)
2089 written &= 0xFFFF;
2090
2091 if (written < wdata->bytes)
2092 wdata->result = -ENOSPC;
2093 else
2094 wdata->bytes = written;
2095 break;
2096 case MID_REQUEST_SUBMITTED:
2097 case MID_RETRY_NEEDED:
2098 wdata->result = -EAGAIN;
2099 break;
2100 default:
2101 wdata->result = -EIO;
2102 break;
2103 }
2104
Jeff Laytonda472fc2012-03-23 14:40:53 -04002105 queue_work(cifsiod_wq, &wdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002106 mutex_lock(&server->srv_mutex);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002107 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002108 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002109 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002110}
2111
2112/* cifs_async_writev - send an async write, and set up mid to handle result */
2113int
Steve French4a5c80d2014-02-07 20:45:12 -06002114cifs_async_writev(struct cifs_writedata *wdata,
2115 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002116{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002117 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002118 WRITE_REQ *smb = NULL;
2119 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002120 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002121 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002122 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002123
2124 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2125 wct = 14;
2126 } else {
2127 wct = 12;
2128 if (wdata->offset >> 32 > 0) {
2129 /* can not handle big offset for old srv */
2130 return -EIO;
2131 }
2132 }
2133
2134 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2135 if (rc)
2136 goto async_writev_out;
2137
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002138 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2139 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002140
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002141 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002142 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002143 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2144 if (wct == 14)
2145 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2146 smb->Reserved = 0xFFFFFFFF;
2147 smb->WriteMode = 0;
2148 smb->Remaining = 0;
2149
2150 smb->DataOffset =
2151 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2152
2153 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002154 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2155 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002156
Jeff Laytoneddb0792012-09-18 16:20:35 -07002157 rqst.rq_iov = &iov;
2158 rqst.rq_nvec = 1;
2159 rqst.rq_pages = wdata->pages;
2160 rqst.rq_npages = wdata->nr_pages;
2161 rqst.rq_pagesz = wdata->pagesz;
2162 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002163
Joe Perchesf96637b2013-05-04 22:12:25 -05002164 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2165 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002166
2167 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2168 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2169
2170 if (wct == 14) {
2171 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2172 put_bcc(wdata->bytes + 1, &smb->hdr);
2173 } else {
2174 /* wct == 12 */
2175 struct smb_com_writex_req *smbw =
2176 (struct smb_com_writex_req *)smb;
2177 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2178 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002179 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002180 }
2181
2182 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002183 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2184 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002185
2186 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002187 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002188 else
Steve French4a5c80d2014-02-07 20:45:12 -06002189 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002190
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002191async_writev_out:
2192 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002193 return rc;
2194}
2195
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002196int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002197CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002198 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199{
2200 int rc = -EACCES;
2201 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002202 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002203 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002204 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002205 __u32 pid = io_parms->pid;
2206 __u16 netfid = io_parms->netfid;
2207 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002208 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002209 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002211 *nbytes = 0;
2212
Joe Perchesf96637b2013-05-04 22:12:25 -05002213 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002214
Steve French4c3130e2008-12-09 00:28:16 +00002215 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002216 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002217 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002218 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002219 if ((offset >> 32) > 0) {
2220 /* can not handle big offset for old srv */
2221 return -EIO;
2222 }
2223 }
Steve French8cc64c62005-10-03 13:49:43 -07002224 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 if (rc)
2226 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002227
2228 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2229 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2230
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 /* tcon and ses pointer are checked in smb_init */
2232 if (tcon->ses->server == NULL)
2233 return -ECONNABORTED;
2234
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002235 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 pSMB->Fid = netfid;
2237 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002238 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002239 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 pSMB->Reserved = 0xFFFFFFFF;
2241 pSMB->WriteMode = 0;
2242 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002243
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002245 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Steve French3e844692005-10-03 13:37:24 -07002247 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2248 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002249 /* header + 1 byte pad */
2250 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002251 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002252 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002253 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002254 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002255 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002256 pSMB->ByteCount = cpu_to_le16(count + 1);
2257 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002258 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002259 (struct smb_com_writex_req *)pSMB;
2260 pSMBW->ByteCount = cpu_to_le16(count + 5);
2261 }
Steve French3e844692005-10-03 13:37:24 -07002262 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002263 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002264 iov[0].iov_len = smb_hdr_len + 4;
2265 else /* wct == 12 pad bigger by four bytes */
2266 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002267
Steve French3e844692005-10-03 13:37:24 -07002268
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002269 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002270 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002272 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002273 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002274 /* presumably this can not happen, but best to be safe */
2275 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002276 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002277 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002278 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2279 *nbytes = (*nbytes) << 16;
2280 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302281
2282 /*
2283 * Mask off high 16 bits when bytes written as returned by the
2284 * server is greater than bytes requested by the client. OS/2
2285 * servers are known to set incorrect CountHigh values.
2286 */
2287 if (*nbytes > count)
2288 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
Steve French4b8f9302006-02-26 16:41:18 +00002291/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002292 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
Steve French50c2f752007-07-13 00:33:32 +00002294 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 since file handle passed in no longer valid */
2296
2297 return rc;
2298}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002299
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002300int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2301 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002302 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2303{
2304 int rc = 0;
2305 LOCK_REQ *pSMB = NULL;
2306 struct kvec iov[2];
2307 int resp_buf_type;
2308 __u16 count;
2309
Joe Perchesf96637b2013-05-04 22:12:25 -05002310 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2311 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002312
2313 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2314 if (rc)
2315 return rc;
2316
2317 pSMB->Timeout = 0;
2318 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2319 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2320 pSMB->LockType = lock_type;
2321 pSMB->AndXCommand = 0xFF; /* none */
2322 pSMB->Fid = netfid; /* netfid stays le */
2323
2324 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2325 inc_rfc1001_len(pSMB, count);
2326 pSMB->ByteCount = cpu_to_le16(count);
2327
2328 iov[0].iov_base = (char *)pSMB;
2329 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2330 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2331 iov[1].iov_base = (char *)buf;
2332 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2333
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002334 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002335 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2336 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002337 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002338
2339 return rc;
2340}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002341
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002343CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002344 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002346 const __u32 numLock, const __u8 lockType,
2347 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348{
2349 int rc = 0;
2350 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002351/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002353 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 __u16 count;
2355
Joe Perchesf96637b2013-05-04 22:12:25 -05002356 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2357 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002358 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2359
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 if (rc)
2361 return rc;
2362
Steve French790fe572007-07-07 19:25:05 +00002363 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002364 /* no response expected */
2365 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002367 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002368 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2370 } else {
2371 pSMB->Timeout = 0;
2372 }
2373
2374 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2375 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2376 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002377 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 pSMB->AndXCommand = 0xFF; /* none */
2379 pSMB->Fid = smb_file_id; /* netfid stays le */
2380
Steve French790fe572007-07-07 19:25:05 +00002381 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002382 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 /* BB where to store pid high? */
2384 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2385 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2386 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2387 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2388 count = sizeof(LOCKING_ANDX_RANGE);
2389 } else {
2390 /* oplock break */
2391 count = 0;
2392 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002393 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 pSMB->ByteCount = cpu_to_le16(count);
2395
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002396 if (waitFlag) {
2397 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002398 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002399 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002400 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002401 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002402 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002403 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002404 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002405 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002406 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
Steve French50c2f752007-07-13 00:33:32 +00002408 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 since file handle passed in no longer valid */
2410 return rc;
2411}
2412
2413int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002414CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002415 const __u16 smb_file_id, const __u32 netpid,
2416 const loff_t start_offset, const __u64 len,
2417 struct file_lock *pLockData, const __u16 lock_type,
2418 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002419{
2420 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2421 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002422 struct cifs_posix_lock *parm_data;
2423 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002424 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002425 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002426 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002427 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002428 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002429
Joe Perchesf96637b2013-05-04 22:12:25 -05002430 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002431
Steve French08547b02006-02-28 22:39:25 +00002432 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2433
2434 if (rc)
2435 return rc;
2436
2437 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2438
Steve French50c2f752007-07-13 00:33:32 +00002439 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002440 pSMB->MaxSetupCount = 0;
2441 pSMB->Reserved = 0;
2442 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002443 pSMB->Reserved2 = 0;
2444 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2445 offset = param_offset + params;
2446
Steve French08547b02006-02-28 22:39:25 +00002447 count = sizeof(struct cifs_posix_lock);
2448 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002449 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002450 pSMB->SetupCount = 1;
2451 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002452 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002453 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2454 else
2455 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2456 byte_count = 3 /* pad */ + params + count;
2457 pSMB->DataCount = cpu_to_le16(count);
2458 pSMB->ParameterCount = cpu_to_le16(params);
2459 pSMB->TotalDataCount = pSMB->DataCount;
2460 pSMB->TotalParameterCount = pSMB->ParameterCount;
2461 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002462 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002463 (((char *) &pSMB->hdr.Protocol) + offset);
2464
2465 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002466 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002467 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002468 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002469 pSMB->Timeout = cpu_to_le32(-1);
2470 } else
2471 pSMB->Timeout = 0;
2472
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002473 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002474 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002475 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002476
2477 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002478 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002479 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2480 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002481 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002482 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002483 if (waitFlag) {
2484 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2485 (struct smb_hdr *) pSMBr, &bytes_returned);
2486 } else {
Steve French133672e2007-11-13 22:41:37 +00002487 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002488 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002489 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2490 &resp_buf_type, timeout);
2491 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2492 not try to free it twice below on exit */
2493 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002494 }
2495
Steve French08547b02006-02-28 22:39:25 +00002496 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002497 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002498 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002499 /* lock structure can be returned on get */
2500 __u16 data_offset;
2501 __u16 data_count;
2502 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002503
Jeff Layton820a8032011-05-04 08:05:26 -04002504 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002505 rc = -EIO; /* bad smb */
2506 goto plk_err_exit;
2507 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002508 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2509 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002510 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002511 rc = -EIO;
2512 goto plk_err_exit;
2513 }
2514 parm_data = (struct cifs_posix_lock *)
2515 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002516 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002517 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002518 else {
2519 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002520 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002521 pLockData->fl_type = F_RDLCK;
2522 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002523 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002524 pLockData->fl_type = F_WRLCK;
2525
Steve French5443d132011-03-13 05:08:25 +00002526 pLockData->fl_start = le64_to_cpu(parm_data->start);
2527 pLockData->fl_end = pLockData->fl_start +
2528 le64_to_cpu(parm_data->length) - 1;
2529 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002530 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002531 }
Steve French50c2f752007-07-13 00:33:32 +00002532
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002533plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002534 if (pSMB)
2535 cifs_small_buf_release(pSMB);
2536
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002537 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French133672e2007-11-13 22:41:37 +00002538
Steve French08547b02006-02-28 22:39:25 +00002539 /* Note: On -EAGAIN error only caller can retry on handle based calls
2540 since file handle passed in no longer valid */
2541
2542 return rc;
2543}
2544
2545
2546int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002547CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548{
2549 int rc = 0;
2550 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002551 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
2553/* do not retry on dead session on close */
2554 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002555 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 return 0;
2557 if (rc)
2558 return rc;
2559
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002561 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002563 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002564 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002566 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002568 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 }
2570 }
2571
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002573 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 rc = 0;
2575
2576 return rc;
2577}
2578
2579int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002580CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002581{
2582 int rc = 0;
2583 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002584 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002585
2586 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2587 if (rc)
2588 return rc;
2589
2590 pSMB->FileID = (__u16) smb_file_id;
2591 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002592 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002593 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002594 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002595 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002596
2597 return rc;
2598}
2599
2600int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002601CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002602 const char *from_name, const char *to_name,
2603 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604{
2605 int rc = 0;
2606 RENAME_REQ *pSMB = NULL;
2607 RENAME_RSP *pSMBr = NULL;
2608 int bytes_returned;
2609 int name_len, name_len2;
2610 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002611 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612
Joe Perchesf96637b2013-05-04 22:12:25 -05002613 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614renameRetry:
2615 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2616 (void **) &pSMBr);
2617 if (rc)
2618 return rc;
2619
2620 pSMB->BufferFormat = 0x04;
2621 pSMB->SearchAttributes =
2622 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2623 ATTR_DIRECTORY);
2624
2625 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002626 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2627 from_name, PATH_MAX,
2628 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 name_len++; /* trailing null */
2630 name_len *= 2;
2631 pSMB->OldFileName[name_len] = 0x04; /* pad */
2632 /* protocol requires ASCII signature byte on Unicode string */
2633 pSMB->OldFileName[name_len + 1] = 0x00;
2634 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002635 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002636 to_name, PATH_MAX, cifs_sb->local_nls,
2637 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2639 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002640 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002641 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002643 strncpy(pSMB->OldFileName, from_name, name_len);
2644 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 name_len2++; /* trailing null */
2646 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002647 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 name_len2++; /* trailing null */
2649 name_len2++; /* signature byte */
2650 }
2651
2652 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002653 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 pSMB->ByteCount = cpu_to_le16(count);
2655
2656 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2657 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002658 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002659 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002660 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 cifs_buf_release(pSMB);
2663
2664 if (rc == -EAGAIN)
2665 goto renameRetry;
2666
2667 return rc;
2668}
2669
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002670int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002671 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002672 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673{
2674 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2675 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002676 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 char *data_offset;
2678 char dummy_string[30];
2679 int rc = 0;
2680 int bytes_returned = 0;
2681 int len_of_str;
2682 __u16 params, param_offset, offset, count, byte_count;
2683
Joe Perchesf96637b2013-05-04 22:12:25 -05002684 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2686 (void **) &pSMBr);
2687 if (rc)
2688 return rc;
2689
2690 params = 6;
2691 pSMB->MaxSetupCount = 0;
2692 pSMB->Reserved = 0;
2693 pSMB->Flags = 0;
2694 pSMB->Timeout = 0;
2695 pSMB->Reserved2 = 0;
2696 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2697 offset = param_offset + params;
2698
2699 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2700 rename_info = (struct set_file_rename *) data_offset;
2701 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002702 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 pSMB->SetupCount = 1;
2704 pSMB->Reserved3 = 0;
2705 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2706 byte_count = 3 /* pad */ + params;
2707 pSMB->ParameterCount = cpu_to_le16(params);
2708 pSMB->TotalParameterCount = pSMB->ParameterCount;
2709 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2710 pSMB->DataOffset = cpu_to_le16(offset);
2711 /* construct random name ".cifs_tmp<inodenum><mid>" */
2712 rename_info->overwrite = cpu_to_le32(1);
2713 rename_info->root_fid = 0;
2714 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002715 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002716 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002717 len_of_str =
2718 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002719 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002721 len_of_str =
2722 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002723 target_name, PATH_MAX, nls_codepage,
2724 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 }
2726 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002727 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 byte_count += count;
2729 pSMB->DataCount = cpu_to_le16(count);
2730 pSMB->TotalDataCount = pSMB->DataCount;
2731 pSMB->Fid = netfid;
2732 pSMB->InformationLevel =
2733 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2734 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002735 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 pSMB->ByteCount = cpu_to_le16(byte_count);
2737 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002738 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002739 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002740 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002741 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2742 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002743
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 cifs_buf_release(pSMB);
2745
2746 /* Note: On -EAGAIN error only caller can retry on handle based calls
2747 since file handle passed in no longer valid */
2748
2749 return rc;
2750}
2751
2752int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002753CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2754 const char *fromName, const __u16 target_tid, const char *toName,
2755 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756{
2757 int rc = 0;
2758 COPY_REQ *pSMB = NULL;
2759 COPY_RSP *pSMBr = NULL;
2760 int bytes_returned;
2761 int name_len, name_len2;
2762 __u16 count;
2763
Joe Perchesf96637b2013-05-04 22:12:25 -05002764 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765copyRetry:
2766 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2767 (void **) &pSMBr);
2768 if (rc)
2769 return rc;
2770
2771 pSMB->BufferFormat = 0x04;
2772 pSMB->Tid2 = target_tid;
2773
2774 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2775
2776 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002777 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2778 fromName, PATH_MAX, nls_codepage,
2779 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 name_len++; /* trailing null */
2781 name_len *= 2;
2782 pSMB->OldFileName[name_len] = 0x04; /* pad */
2783 /* protocol requires ASCII signature byte on Unicode string */
2784 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002785 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002786 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2787 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2789 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002790 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 name_len = strnlen(fromName, PATH_MAX);
2792 name_len++; /* trailing null */
2793 strncpy(pSMB->OldFileName, fromName, name_len);
2794 name_len2 = strnlen(toName, PATH_MAX);
2795 name_len2++; /* trailing null */
2796 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2797 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2798 name_len2++; /* trailing null */
2799 name_len2++; /* signature byte */
2800 }
2801
2802 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002803 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 pSMB->ByteCount = cpu_to_le16(count);
2805
2806 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2807 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2808 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002809 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2810 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 }
Steve French0d817bc2008-05-22 02:02:03 +00002812 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
2814 if (rc == -EAGAIN)
2815 goto copyRetry;
2816
2817 return rc;
2818}
2819
2820int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002821CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002823 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824{
2825 TRANSACTION2_SPI_REQ *pSMB = NULL;
2826 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2827 char *data_offset;
2828 int name_len;
2829 int name_len_target;
2830 int rc = 0;
2831 int bytes_returned = 0;
2832 __u16 params, param_offset, offset, byte_count;
2833
Joe Perchesf96637b2013-05-04 22:12:25 -05002834 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835createSymLinkRetry:
2836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2837 (void **) &pSMBr);
2838 if (rc)
2839 return rc;
2840
2841 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2842 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002843 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2844 /* find define for this maxpathcomponent */
2845 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 name_len++; /* trailing null */
2847 name_len *= 2;
2848
Steve French50c2f752007-07-13 00:33:32 +00002849 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 name_len = strnlen(fromName, PATH_MAX);
2851 name_len++; /* trailing null */
2852 strncpy(pSMB->FileName, fromName, name_len);
2853 }
2854 params = 6 + name_len;
2855 pSMB->MaxSetupCount = 0;
2856 pSMB->Reserved = 0;
2857 pSMB->Flags = 0;
2858 pSMB->Timeout = 0;
2859 pSMB->Reserved2 = 0;
2860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002861 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 offset = param_offset + params;
2863
2864 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2866 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002867 cifsConvertToUTF16((__le16 *) data_offset, toName,
2868 /* find define for this maxpathcomponent */
2869 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 name_len_target++; /* trailing null */
2871 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002872 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 name_len_target = strnlen(toName, PATH_MAX);
2874 name_len_target++; /* trailing null */
2875 strncpy(data_offset, toName, name_len_target);
2876 }
2877
2878 pSMB->MaxParameterCount = cpu_to_le16(2);
2879 /* BB find exact max on data count below from sess */
2880 pSMB->MaxDataCount = cpu_to_le16(1000);
2881 pSMB->SetupCount = 1;
2882 pSMB->Reserved3 = 0;
2883 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2884 byte_count = 3 /* pad */ + params + name_len_target;
2885 pSMB->DataCount = cpu_to_le16(name_len_target);
2886 pSMB->ParameterCount = cpu_to_le16(params);
2887 pSMB->TotalDataCount = pSMB->DataCount;
2888 pSMB->TotalParameterCount = pSMB->ParameterCount;
2889 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2890 pSMB->DataOffset = cpu_to_le16(offset);
2891 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2892 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002893 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 pSMB->ByteCount = cpu_to_le16(byte_count);
2895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002897 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002898 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002899 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2900 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Steve French0d817bc2008-05-22 02:02:03 +00002902 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
2904 if (rc == -EAGAIN)
2905 goto createSymLinkRetry;
2906
2907 return rc;
2908}
2909
2910int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002911CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002913 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914{
2915 TRANSACTION2_SPI_REQ *pSMB = NULL;
2916 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2917 char *data_offset;
2918 int name_len;
2919 int name_len_target;
2920 int rc = 0;
2921 int bytes_returned = 0;
2922 __u16 params, param_offset, offset, byte_count;
2923
Joe Perchesf96637b2013-05-04 22:12:25 -05002924 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925createHardLinkRetry:
2926 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2927 (void **) &pSMBr);
2928 if (rc)
2929 return rc;
2930
2931 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002932 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2933 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 name_len++; /* trailing null */
2935 name_len *= 2;
2936
Steve French50c2f752007-07-13 00:33:32 +00002937 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 name_len = strnlen(toName, PATH_MAX);
2939 name_len++; /* trailing null */
2940 strncpy(pSMB->FileName, toName, name_len);
2941 }
2942 params = 6 + name_len;
2943 pSMB->MaxSetupCount = 0;
2944 pSMB->Reserved = 0;
2945 pSMB->Flags = 0;
2946 pSMB->Timeout = 0;
2947 pSMB->Reserved2 = 0;
2948 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002949 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 offset = param_offset + params;
2951
2952 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2954 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002955 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2956 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 name_len_target++; /* trailing null */
2958 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002959 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len_target = strnlen(fromName, PATH_MAX);
2961 name_len_target++; /* trailing null */
2962 strncpy(data_offset, fromName, name_len_target);
2963 }
2964
2965 pSMB->MaxParameterCount = cpu_to_le16(2);
2966 /* BB find exact max on data count below from sess*/
2967 pSMB->MaxDataCount = cpu_to_le16(1000);
2968 pSMB->SetupCount = 1;
2969 pSMB->Reserved3 = 0;
2970 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2971 byte_count = 3 /* pad */ + params + name_len_target;
2972 pSMB->ParameterCount = cpu_to_le16(params);
2973 pSMB->TotalParameterCount = pSMB->ParameterCount;
2974 pSMB->DataCount = cpu_to_le16(name_len_target);
2975 pSMB->TotalDataCount = pSMB->DataCount;
2976 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2977 pSMB->DataOffset = cpu_to_le16(offset);
2978 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2979 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002980 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 pSMB->ByteCount = cpu_to_le16(byte_count);
2982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002984 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002985 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002986 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2987 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988
2989 cifs_buf_release(pSMB);
2990 if (rc == -EAGAIN)
2991 goto createHardLinkRetry;
2992
2993 return rc;
2994}
2995
2996int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002997CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002998 const char *from_name, const char *to_name,
2999 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000{
3001 int rc = 0;
3002 NT_RENAME_REQ *pSMB = NULL;
3003 RENAME_RSP *pSMBr = NULL;
3004 int bytes_returned;
3005 int name_len, name_len2;
3006 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003007 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
Joe Perchesf96637b2013-05-04 22:12:25 -05003009 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010winCreateHardLinkRetry:
3011
3012 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3013 (void **) &pSMBr);
3014 if (rc)
3015 return rc;
3016
3017 pSMB->SearchAttributes =
3018 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3019 ATTR_DIRECTORY);
3020 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3021 pSMB->ClusterCount = 0;
3022
3023 pSMB->BufferFormat = 0x04;
3024
3025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3026 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003027 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3028 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 name_len++; /* trailing null */
3030 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003031
3032 /* protocol specifies ASCII buffer format (0x04) for unicode */
3033 pSMB->OldFileName[name_len] = 0x04;
3034 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003036 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003037 to_name, PATH_MAX, cifs_sb->local_nls,
3038 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3040 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003041 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003042 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003044 strncpy(pSMB->OldFileName, from_name, name_len);
3045 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 name_len2++; /* trailing null */
3047 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003048 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 name_len2++; /* trailing null */
3050 name_len2++; /* signature byte */
3051 }
3052
3053 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003054 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 pSMB->ByteCount = cpu_to_le16(count);
3056
3057 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3058 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003059 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003060 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003061 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003062
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 cifs_buf_release(pSMB);
3064 if (rc == -EAGAIN)
3065 goto winCreateHardLinkRetry;
3066
3067 return rc;
3068}
3069
3070int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003071CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003072 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003073 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074{
3075/* SMB_QUERY_FILE_UNIX_LINK */
3076 TRANSACTION2_QPI_REQ *pSMB = NULL;
3077 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3078 int rc = 0;
3079 int bytes_returned;
3080 int name_len;
3081 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003082 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
Joe Perchesf96637b2013-05-04 22:12:25 -05003084 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
3086querySymLinkRetry:
3087 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3088 (void **) &pSMBr);
3089 if (rc)
3090 return rc;
3091
3092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3093 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003094 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3095 searchName, PATH_MAX, nls_codepage,
3096 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 name_len++; /* trailing null */
3098 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003099 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 name_len = strnlen(searchName, PATH_MAX);
3101 name_len++; /* trailing null */
3102 strncpy(pSMB->FileName, searchName, name_len);
3103 }
3104
3105 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3106 pSMB->TotalDataCount = 0;
3107 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003108 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 pSMB->MaxSetupCount = 0;
3110 pSMB->Reserved = 0;
3111 pSMB->Flags = 0;
3112 pSMB->Timeout = 0;
3113 pSMB->Reserved2 = 0;
3114 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003115 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 pSMB->DataCount = 0;
3117 pSMB->DataOffset = 0;
3118 pSMB->SetupCount = 1;
3119 pSMB->Reserved3 = 0;
3120 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3121 byte_count = params + 1 /* pad */ ;
3122 pSMB->TotalParameterCount = cpu_to_le16(params);
3123 pSMB->ParameterCount = pSMB->TotalParameterCount;
3124 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3125 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003126 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 pSMB->ByteCount = cpu_to_le16(byte_count);
3128
3129 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3130 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3131 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003132 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 } else {
3134 /* decode response */
3135
3136 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003138 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003139 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003141 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003142 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
Jeff Layton460b9692009-04-30 07:17:56 -04003144 data_start = ((char *) &pSMBr->hdr.Protocol) +
3145 le16_to_cpu(pSMBr->t2.DataOffset);
3146
Steve French0e0d2cf2009-05-01 05:27:32 +00003147 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3148 is_unicode = true;
3149 else
3150 is_unicode = false;
3151
Steve French737b7582005-04-28 22:41:06 -07003152 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003153 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3154 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003155 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003156 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 }
3158 }
3159 cifs_buf_release(pSMB);
3160 if (rc == -EAGAIN)
3161 goto querySymLinkRetry;
3162 return rc;
3163}
3164
Steve Frenchc52a9552011-02-24 06:16:22 +00003165/*
3166 * Recent Windows versions now create symlinks more frequently
3167 * and they use the "reparse point" mechanism below. We can of course
3168 * do symlinks nicely to Samba and other servers which support the
3169 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3170 * "MF" symlinks optionally, but for recent Windows we really need to
3171 * reenable the code below and fix the cifs_symlink callers to handle this.
3172 * In the interim this code has been moved to its own config option so
3173 * it is not compiled in by default until callers fixed up and more tested.
3174 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003176CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3177 __u16 fid, char **symlinkinfo,
3178 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179{
3180 int rc = 0;
3181 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003182 struct smb_com_transaction_ioctl_req *pSMB;
3183 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003184 bool is_unicode;
3185 unsigned int sub_len;
3186 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003187 struct reparse_symlink_data *reparse_buf;
3188 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003189 __u32 data_offset, data_count;
3190 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003192 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3194 (void **) &pSMBr);
3195 if (rc)
3196 return rc;
3197
3198 pSMB->TotalParameterCount = 0 ;
3199 pSMB->TotalDataCount = 0;
3200 pSMB->MaxParameterCount = cpu_to_le32(2);
3201 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003202 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 pSMB->MaxSetupCount = 4;
3204 pSMB->Reserved = 0;
3205 pSMB->ParameterOffset = 0;
3206 pSMB->DataCount = 0;
3207 pSMB->DataOffset = 0;
3208 pSMB->SetupCount = 4;
3209 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3210 pSMB->ParameterCount = pSMB->TotalParameterCount;
3211 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3212 pSMB->IsFsctl = 1; /* FSCTL */
3213 pSMB->IsRootFlag = 0;
3214 pSMB->Fid = fid; /* file handle always le */
3215 pSMB->ByteCount = 0;
3216
3217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3219 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003220 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003221 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 }
Steve French989c7e52009-05-02 05:32:20 +00003223
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003224 data_offset = le32_to_cpu(pSMBr->DataOffset);
3225 data_count = le32_to_cpu(pSMBr->DataCount);
3226 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3227 /* BB also check enough total bytes returned */
3228 rc = -EIO; /* bad smb */
3229 goto qreparse_out;
3230 }
3231 if (!data_count || (data_count > 2048)) {
3232 rc = -EIO;
3233 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3234 goto qreparse_out;
3235 }
3236 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003237 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003238 ((char *)&pSMBr->hdr.Protocol + data_offset);
3239 if ((char *)reparse_buf >= end_of_smb) {
3240 rc = -EIO;
3241 goto qreparse_out;
3242 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003243 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3244 cifs_dbg(FYI, "NFS style reparse tag\n");
3245 posix_buf = (struct reparse_posix_data *)reparse_buf;
3246
3247 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3248 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3249 le64_to_cpu(posix_buf->InodeType));
3250 rc = -EOPNOTSUPP;
3251 goto qreparse_out;
3252 }
3253 is_unicode = true;
3254 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3255 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3256 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3257 rc = -EIO;
3258 goto qreparse_out;
3259 }
3260 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3261 sub_len, is_unicode, nls_codepage);
3262 goto qreparse_out;
3263 } else if (reparse_buf->ReparseTag !=
3264 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3265 rc = -EOPNOTSUPP;
3266 goto qreparse_out;
3267 }
3268
3269 /* Reparse tag is NTFS symlink */
3270 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3271 reparse_buf->PathBuffer;
3272 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3273 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003274 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3275 rc = -EIO;
3276 goto qreparse_out;
3277 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003278 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3279 is_unicode = true;
3280 else
3281 is_unicode = false;
3282
3283 /* BB FIXME investigate remapping reserved chars here */
3284 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3285 nls_codepage);
3286 if (!*symlinkinfo)
3287 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003289 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003291 /*
3292 * Note: On -EAGAIN error only caller can retry on handle based calls
3293 * since file handle passed in no longer valid.
3294 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 return rc;
3296}
3297
Steve Frenchc7f508a2013-10-14 15:27:32 -05003298int
3299CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3300 __u16 fid)
3301{
3302 int rc = 0;
3303 int bytes_returned;
3304 struct smb_com_transaction_compr_ioctl_req *pSMB;
3305 struct smb_com_transaction_ioctl_rsp *pSMBr;
3306
3307 cifs_dbg(FYI, "Set compression for %u\n", fid);
3308 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3309 (void **) &pSMBr);
3310 if (rc)
3311 return rc;
3312
3313 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3314
3315 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003316 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003317 pSMB->MaxParameterCount = 0;
3318 pSMB->MaxDataCount = 0;
3319 pSMB->MaxSetupCount = 4;
3320 pSMB->Reserved = 0;
3321 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003322 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003323 pSMB->DataOffset =
3324 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3325 compression_state) - 4); /* 84 */
3326 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003327 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003328 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003329 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003330 pSMB->IsFsctl = 1; /* FSCTL */
3331 pSMB->IsRootFlag = 0;
3332 pSMB->Fid = fid; /* file handle always le */
3333 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003334 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003335 inc_rfc1001_len(pSMB, 5);
3336
3337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3339 if (rc)
3340 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3341
3342 cifs_buf_release(pSMB);
3343
3344 /*
3345 * Note: On -EAGAIN error only caller can retry on handle based calls
3346 * since file handle passed in no longer valid.
3347 */
3348 return rc;
3349}
3350
3351
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352#ifdef CONFIG_CIFS_POSIX
3353
3354/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003355static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003356 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357{
3358 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003359 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3360 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3361 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003362/*
3363 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3364 ace->e_perm, ace->e_tag, ace->e_id);
3365*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
3367 return;
3368}
3369
3370/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003371static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3372 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373{
3374 int size = 0;
3375 int i;
3376 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003377 struct cifs_posix_ace *pACE;
3378 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003379 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380
3381 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3382 return -EOPNOTSUPP;
3383
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003384 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 count = le16_to_cpu(cifs_acl->access_entry_count);
3386 pACE = &cifs_acl->ace_array[0];
3387 size = sizeof(struct cifs_posix_acl);
3388 size += sizeof(struct cifs_posix_ace) * count;
3389 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003390 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003391 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3392 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 return -EINVAL;
3394 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003395 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 count = le16_to_cpu(cifs_acl->access_entry_count);
3397 size = sizeof(struct cifs_posix_acl);
3398 size += sizeof(struct cifs_posix_ace) * count;
3399/* skip past access ACEs to get to default ACEs */
3400 pACE = &cifs_acl->ace_array[count];
3401 count = le16_to_cpu(cifs_acl->default_entry_count);
3402 size += sizeof(struct cifs_posix_ace) * count;
3403 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003404 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 return -EINVAL;
3406 } else {
3407 /* illegal type */
3408 return -EINVAL;
3409 }
3410
3411 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003412 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003413 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003414 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 return -ERANGE;
3416 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003417 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3418
Steve Frenchff7feac2005-11-15 16:45:16 -08003419 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003420 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003421 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003422 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 }
3424 }
3425 return size;
3426}
3427
Steve French50c2f752007-07-13 00:33:32 +00003428static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003429 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430{
3431 __u16 rc = 0; /* 0 = ACL converted ok */
3432
Steve Frenchff7feac2005-11-15 16:45:16 -08003433 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3434 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003436 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 /* Probably no need to le convert -1 on any arch but can not hurt */
3438 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003439 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003440 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003441/*
3442 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3443 ace->e_perm, ace->e_tag, ace->e_id);
3444*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 return rc;
3446}
3447
3448/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003449static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3450 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451{
3452 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003453 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003454 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003455 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 int count;
3457 int i;
3458
Steve French790fe572007-07-07 19:25:05 +00003459 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 return 0;
3461
3462 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003463 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3464 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003465 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003466 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3467 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 return 0;
3469 }
3470 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003471 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003472 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003473 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003474 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003475 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003476 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003477 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003478 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 return 0;
3480 }
Steve French50c2f752007-07-13 00:33:32 +00003481 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003482 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003483 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 /* ACE not converted */
3485 break;
3486 }
3487 }
Steve French790fe572007-07-07 19:25:05 +00003488 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3490 rc += sizeof(struct cifs_posix_acl);
3491 /* BB add check to make sure ACL does not overflow SMB */
3492 }
3493 return rc;
3494}
3495
3496int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003497CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003498 const unsigned char *searchName,
3499 char *acl_inf, const int buflen, const int acl_type,
3500 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501{
3502/* SMB_QUERY_POSIX_ACL */
3503 TRANSACTION2_QPI_REQ *pSMB = NULL;
3504 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3505 int rc = 0;
3506 int bytes_returned;
3507 int name_len;
3508 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003509
Joe Perchesf96637b2013-05-04 22:12:25 -05003510 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511
3512queryAclRetry:
3513 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3514 (void **) &pSMBr);
3515 if (rc)
3516 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003517
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3519 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003520 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3521 searchName, PATH_MAX, nls_codepage,
3522 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 name_len++; /* trailing null */
3524 name_len *= 2;
3525 pSMB->FileName[name_len] = 0;
3526 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003527 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 name_len = strnlen(searchName, PATH_MAX);
3529 name_len++; /* trailing null */
3530 strncpy(pSMB->FileName, searchName, name_len);
3531 }
3532
3533 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3534 pSMB->TotalDataCount = 0;
3535 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003536 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 pSMB->MaxDataCount = cpu_to_le16(4000);
3538 pSMB->MaxSetupCount = 0;
3539 pSMB->Reserved = 0;
3540 pSMB->Flags = 0;
3541 pSMB->Timeout = 0;
3542 pSMB->Reserved2 = 0;
3543 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003544 offsetof(struct smb_com_transaction2_qpi_req,
3545 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 pSMB->DataCount = 0;
3547 pSMB->DataOffset = 0;
3548 pSMB->SetupCount = 1;
3549 pSMB->Reserved3 = 0;
3550 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3551 byte_count = params + 1 /* pad */ ;
3552 pSMB->TotalParameterCount = cpu_to_le16(params);
3553 pSMB->ParameterCount = pSMB->TotalParameterCount;
3554 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3555 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003556 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 pSMB->ByteCount = cpu_to_le16(byte_count);
3558
3559 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3560 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003561 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003563 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 } else {
3565 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003566
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003569 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 rc = -EIO; /* bad smb */
3571 else {
3572 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3573 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3574 rc = cifs_copy_posix_acl(acl_inf,
3575 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003576 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 }
3578 }
3579 cifs_buf_release(pSMB);
3580 if (rc == -EAGAIN)
3581 goto queryAclRetry;
3582 return rc;
3583}
3584
3585int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003586CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003587 const unsigned char *fileName,
3588 const char *local_acl, const int buflen,
3589 const int acl_type,
3590 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591{
3592 struct smb_com_transaction2_spi_req *pSMB = NULL;
3593 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3594 char *parm_data;
3595 int name_len;
3596 int rc = 0;
3597 int bytes_returned = 0;
3598 __u16 params, byte_count, data_count, param_offset, offset;
3599
Joe Perchesf96637b2013-05-04 22:12:25 -05003600 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601setAclRetry:
3602 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003603 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 if (rc)
3605 return rc;
3606 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3607 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003608 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3609 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 name_len++; /* trailing null */
3611 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003612 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 name_len = strnlen(fileName, PATH_MAX);
3614 name_len++; /* trailing null */
3615 strncpy(pSMB->FileName, fileName, name_len);
3616 }
3617 params = 6 + name_len;
3618 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003619 /* BB find max SMB size from sess */
3620 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 pSMB->MaxSetupCount = 0;
3622 pSMB->Reserved = 0;
3623 pSMB->Flags = 0;
3624 pSMB->Timeout = 0;
3625 pSMB->Reserved2 = 0;
3626 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003627 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 offset = param_offset + params;
3629 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3630 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3631
3632 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003633 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634
Steve French790fe572007-07-07 19:25:05 +00003635 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 rc = -EOPNOTSUPP;
3637 goto setACLerrorExit;
3638 }
3639 pSMB->DataOffset = cpu_to_le16(offset);
3640 pSMB->SetupCount = 1;
3641 pSMB->Reserved3 = 0;
3642 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3643 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3644 byte_count = 3 /* pad */ + params + data_count;
3645 pSMB->DataCount = cpu_to_le16(data_count);
3646 pSMB->TotalDataCount = pSMB->DataCount;
3647 pSMB->ParameterCount = cpu_to_le16(params);
3648 pSMB->TotalParameterCount = pSMB->ParameterCount;
3649 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003650 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 pSMB->ByteCount = cpu_to_le16(byte_count);
3652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003654 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003655 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656
3657setACLerrorExit:
3658 cifs_buf_release(pSMB);
3659 if (rc == -EAGAIN)
3660 goto setAclRetry;
3661 return rc;
3662}
3663
Steve Frenchf654bac2005-04-28 22:41:04 -07003664/* BB fix tabs in this function FIXME BB */
3665int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003666CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003667 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003668{
Steve French50c2f752007-07-13 00:33:32 +00003669 int rc = 0;
3670 struct smb_t2_qfi_req *pSMB = NULL;
3671 struct smb_t2_qfi_rsp *pSMBr = NULL;
3672 int bytes_returned;
3673 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003674
Joe Perchesf96637b2013-05-04 22:12:25 -05003675 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003676 if (tcon == NULL)
3677 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003678
3679GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003680 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3681 (void **) &pSMBr);
3682 if (rc)
3683 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003684
Steve Frenchad7a2922008-02-07 23:25:02 +00003685 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003686 pSMB->t2.TotalDataCount = 0;
3687 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3688 /* BB find exact max data count below from sess structure BB */
3689 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3690 pSMB->t2.MaxSetupCount = 0;
3691 pSMB->t2.Reserved = 0;
3692 pSMB->t2.Flags = 0;
3693 pSMB->t2.Timeout = 0;
3694 pSMB->t2.Reserved2 = 0;
3695 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3696 Fid) - 4);
3697 pSMB->t2.DataCount = 0;
3698 pSMB->t2.DataOffset = 0;
3699 pSMB->t2.SetupCount = 1;
3700 pSMB->t2.Reserved3 = 0;
3701 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3702 byte_count = params + 1 /* pad */ ;
3703 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3704 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3705 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3706 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003707 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003708 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003709 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003710
Steve French790fe572007-07-07 19:25:05 +00003711 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3712 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3713 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003714 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003715 } else {
3716 /* decode response */
3717 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003718 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003719 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003720 /* If rc should we check for EOPNOSUPP and
3721 disable the srvino flag? or in caller? */
3722 rc = -EIO; /* bad smb */
3723 else {
3724 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3725 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3726 struct file_chattr_info *pfinfo;
3727 /* BB Do we need a cast or hash here ? */
3728 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003729 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003730 rc = -EIO;
3731 goto GetExtAttrOut;
3732 }
3733 pfinfo = (struct file_chattr_info *)
3734 (data_offset + (char *) &pSMBr->hdr.Protocol);
3735 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003736 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003737 }
3738 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003739GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003740 cifs_buf_release(pSMB);
3741 if (rc == -EAGAIN)
3742 goto GetExtAttrRetry;
3743 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003744}
3745
Steve Frenchf654bac2005-04-28 22:41:04 -07003746#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747
Jeff Layton79df1ba2010-12-06 12:52:08 -05003748#ifdef CONFIG_CIFS_ACL
3749/*
3750 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3751 * all NT TRANSACTS that we init here have total parm and data under about 400
3752 * bytes (to fit in small cifs buffer size), which is the case so far, it
3753 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3754 * returned setup area) and MaxParameterCount (returned parms size) must be set
3755 * by caller
3756 */
3757static int
3758smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003759 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003760 void **ret_buf)
3761{
3762 int rc;
3763 __u32 temp_offset;
3764 struct smb_com_ntransact_req *pSMB;
3765
3766 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3767 (void **)&pSMB);
3768 if (rc)
3769 return rc;
3770 *ret_buf = (void *)pSMB;
3771 pSMB->Reserved = 0;
3772 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3773 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003774 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003775 pSMB->ParameterCount = pSMB->TotalParameterCount;
3776 pSMB->DataCount = pSMB->TotalDataCount;
3777 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3778 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3779 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3780 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3781 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3782 pSMB->SubCommand = cpu_to_le16(sub_command);
3783 return 0;
3784}
3785
3786static int
3787validate_ntransact(char *buf, char **ppparm, char **ppdata,
3788 __u32 *pparmlen, __u32 *pdatalen)
3789{
3790 char *end_of_smb;
3791 __u32 data_count, data_offset, parm_count, parm_offset;
3792 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003793 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003794
3795 *pdatalen = 0;
3796 *pparmlen = 0;
3797
3798 if (buf == NULL)
3799 return -EINVAL;
3800
3801 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3802
Jeff Layton820a8032011-05-04 08:05:26 -04003803 bcc = get_bcc(&pSMBr->hdr);
3804 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003805 (char *)&pSMBr->ByteCount;
3806
3807 data_offset = le32_to_cpu(pSMBr->DataOffset);
3808 data_count = le32_to_cpu(pSMBr->DataCount);
3809 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3810 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3811
3812 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3813 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3814
3815 /* should we also check that parm and data areas do not overlap? */
3816 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003817 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003818 return -EINVAL;
3819 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003820 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003821 return -EINVAL;
3822 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003823 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003824 return -EINVAL;
3825 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003826 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3827 *ppdata, data_count, (data_count + *ppdata),
3828 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003829 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003830 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003831 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003832 return -EINVAL;
3833 }
3834 *pdatalen = data_count;
3835 *pparmlen = parm_count;
3836 return 0;
3837}
3838
Steve French0a4b92c2006-01-12 15:44:21 -08003839/* Get Security Descriptor (by handle) from remote server for a file or dir */
3840int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003841CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003842 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003843{
3844 int rc = 0;
3845 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003846 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003847 struct kvec iov[1];
3848
Joe Perchesf96637b2013-05-04 22:12:25 -05003849 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003850
Steve French630f3f0c2007-10-25 21:17:17 +00003851 *pbuflen = 0;
3852 *acl_inf = NULL;
3853
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003854 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003855 8 /* parm len */, tcon, (void **) &pSMB);
3856 if (rc)
3857 return rc;
3858
3859 pSMB->MaxParameterCount = cpu_to_le32(4);
3860 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3861 pSMB->MaxSetupCount = 0;
3862 pSMB->Fid = fid; /* file handle always le */
3863 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3864 CIFS_ACL_DACL);
3865 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003866 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003867 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003868 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003869
Steve Frencha761ac52007-10-18 21:45:27 +00003870 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003871 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003872 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003873 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003874 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003875 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003876 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003877 __u32 parm_len;
3878 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003879 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003880 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003881
3882/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003883 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003884 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003885 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003886 goto qsec_out;
3887 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3888
Joe Perchesf96637b2013-05-04 22:12:25 -05003889 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3890 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003891
3892 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3893 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003894 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003895 goto qsec_out;
3896 }
3897
3898/* BB check that data area is minimum length and as big as acl_len */
3899
Steve Frenchaf6f4612007-10-16 18:40:37 +00003900 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003901 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003902 cifs_dbg(VFS, "acl length %d does not match %d\n",
3903 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003904 if (*pbuflen > acl_len)
3905 *pbuflen = acl_len;
3906 }
Steve French0a4b92c2006-01-12 15:44:21 -08003907
Steve French630f3f0c2007-10-25 21:17:17 +00003908 /* check if buffer is big enough for the acl
3909 header followed by the smallest SID */
3910 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3911 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003912 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003913 rc = -EINVAL;
3914 *pbuflen = 0;
3915 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003916 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003917 if (*acl_inf == NULL) {
3918 *pbuflen = 0;
3919 rc = -ENOMEM;
3920 }
Steve French630f3f0c2007-10-25 21:17:17 +00003921 }
Steve French0a4b92c2006-01-12 15:44:21 -08003922 }
3923qsec_out:
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01003924 free_rsp_buf(buf_type, iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003925/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003926 return rc;
3927}
Steve French97837582007-12-31 07:47:21 +00003928
3929int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003930CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003931 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003932{
3933 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3934 int rc = 0;
3935 int bytes_returned = 0;
3936 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003937 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003938
3939setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003940 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003941 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003942 return rc;
Steve French97837582007-12-31 07:47:21 +00003943
3944 pSMB->MaxSetupCount = 0;
3945 pSMB->Reserved = 0;
3946
3947 param_count = 8;
3948 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3949 data_count = acllen;
3950 data_offset = param_offset + param_count;
3951 byte_count = 3 /* pad */ + param_count;
3952
3953 pSMB->DataCount = cpu_to_le32(data_count);
3954 pSMB->TotalDataCount = pSMB->DataCount;
3955 pSMB->MaxParameterCount = cpu_to_le32(4);
3956 pSMB->MaxDataCount = cpu_to_le32(16384);
3957 pSMB->ParameterCount = cpu_to_le32(param_count);
3958 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3959 pSMB->TotalParameterCount = pSMB->ParameterCount;
3960 pSMB->DataOffset = cpu_to_le32(data_offset);
3961 pSMB->SetupCount = 0;
3962 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3963 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3964
3965 pSMB->Fid = fid; /* file handle always le */
3966 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003967 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003968
3969 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003970 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3971 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003972 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003973 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003974 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003975
3976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3978
Joe Perchesf96637b2013-05-04 22:12:25 -05003979 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3980 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003981 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003982 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003983 cifs_buf_release(pSMB);
3984
3985 if (rc == -EAGAIN)
3986 goto setCifsAclRetry;
3987
3988 return (rc);
3989}
3990
Jeff Layton79df1ba2010-12-06 12:52:08 -05003991#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003992
Steve French6b8edfe2005-08-23 20:26:03 -07003993/* Legacy Query Path Information call for lookup to old servers such
3994 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003995int
3996SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3997 const char *search_name, FILE_ALL_INFO *data,
3998 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003999{
Steve Frenchad7a2922008-02-07 23:25:02 +00004000 QUERY_INFORMATION_REQ *pSMB;
4001 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004002 int rc = 0;
4003 int bytes_returned;
4004 int name_len;
4005
Joe Perchesf96637b2013-05-04 22:12:25 -05004006 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004007QInfRetry:
4008 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004009 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004010 if (rc)
4011 return rc;
4012
4013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4014 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004015 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004016 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004017 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004018 name_len++; /* trailing null */
4019 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004020 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004021 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004022 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004023 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004024 }
4025 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004026 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004027 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004028 pSMB->ByteCount = cpu_to_le16(name_len);
4029
4030 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004031 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004032 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004033 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004034 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004035 struct timespec ts;
4036 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004037
4038 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004039 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004040 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004041 ts.tv_nsec = 0;
4042 ts.tv_sec = time;
4043 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004044 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4045 data->LastWriteTime = data->ChangeTime;
4046 data->LastAccessTime = 0;
4047 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004048 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004049 data->EndOfFile = data->AllocationSize;
4050 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004051 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004052 } else
4053 rc = -EIO; /* bad buffer passed in */
4054
4055 cifs_buf_release(pSMB);
4056
4057 if (rc == -EAGAIN)
4058 goto QInfRetry;
4059
4060 return rc;
4061}
4062
Jeff Laytonbcd53572010-02-12 07:44:16 -05004063int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004064CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004065 u16 netfid, FILE_ALL_INFO *pFindData)
4066{
4067 struct smb_t2_qfi_req *pSMB = NULL;
4068 struct smb_t2_qfi_rsp *pSMBr = NULL;
4069 int rc = 0;
4070 int bytes_returned;
4071 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004072
Jeff Laytonbcd53572010-02-12 07:44:16 -05004073QFileInfoRetry:
4074 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4075 (void **) &pSMBr);
4076 if (rc)
4077 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004078
Jeff Laytonbcd53572010-02-12 07:44:16 -05004079 params = 2 /* level */ + 2 /* fid */;
4080 pSMB->t2.TotalDataCount = 0;
4081 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4082 /* BB find exact max data count below from sess structure BB */
4083 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4084 pSMB->t2.MaxSetupCount = 0;
4085 pSMB->t2.Reserved = 0;
4086 pSMB->t2.Flags = 0;
4087 pSMB->t2.Timeout = 0;
4088 pSMB->t2.Reserved2 = 0;
4089 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4090 Fid) - 4);
4091 pSMB->t2.DataCount = 0;
4092 pSMB->t2.DataOffset = 0;
4093 pSMB->t2.SetupCount = 1;
4094 pSMB->t2.Reserved3 = 0;
4095 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4096 byte_count = params + 1 /* pad */ ;
4097 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4098 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4099 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4100 pSMB->Pad = 0;
4101 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004102 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004103 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004104
4105 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4106 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4107 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004108 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004109 } else { /* decode response */
4110 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4111
4112 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4113 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004114 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004115 rc = -EIO; /* bad smb */
4116 else if (pFindData) {
4117 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4118 memcpy((char *) pFindData,
4119 (char *) &pSMBr->hdr.Protocol +
4120 data_offset, sizeof(FILE_ALL_INFO));
4121 } else
4122 rc = -ENOMEM;
4123 }
4124 cifs_buf_release(pSMB);
4125 if (rc == -EAGAIN)
4126 goto QFileInfoRetry;
4127
4128 return rc;
4129}
Steve French6b8edfe2005-08-23 20:26:03 -07004130
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004132CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004133 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004134 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004135 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004137 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 TRANSACTION2_QPI_REQ *pSMB = NULL;
4139 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4140 int rc = 0;
4141 int bytes_returned;
4142 int name_len;
4143 __u16 params, byte_count;
4144
Joe Perchesf96637b2013-05-04 22:12:25 -05004145 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146QPathInfoRetry:
4147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4148 (void **) &pSMBr);
4149 if (rc)
4150 return rc;
4151
4152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4153 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004154 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004155 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 name_len++; /* trailing null */
4157 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004158 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004159 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004161 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 }
4163
Steve French50c2f752007-07-13 00:33:32 +00004164 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 pSMB->TotalDataCount = 0;
4166 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004167 /* BB find exact max SMB PDU from sess structure BB */
4168 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 pSMB->MaxSetupCount = 0;
4170 pSMB->Reserved = 0;
4171 pSMB->Flags = 0;
4172 pSMB->Timeout = 0;
4173 pSMB->Reserved2 = 0;
4174 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004175 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 pSMB->DataCount = 0;
4177 pSMB->DataOffset = 0;
4178 pSMB->SetupCount = 1;
4179 pSMB->Reserved3 = 0;
4180 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4181 byte_count = params + 1 /* pad */ ;
4182 pSMB->TotalParameterCount = cpu_to_le16(params);
4183 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004184 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004185 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4186 else
4187 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004189 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 pSMB->ByteCount = cpu_to_le16(byte_count);
4191
4192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4194 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004195 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 } else { /* decode response */
4197 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4198
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004199 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4200 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004201 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004203 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004204 rc = -EIO; /* 24 or 26 expected but we do not read
4205 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004206 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004207 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004209
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004210 /*
4211 * On legacy responses we do not read the last field,
4212 * EAsize, fortunately since it varies by subdialect and
4213 * also note it differs on Set vs Get, ie two bytes or 4
4214 * bytes depending but we don't care here.
4215 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004216 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004217 size = sizeof(FILE_INFO_STANDARD);
4218 else
4219 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004220 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004221 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 } else
4223 rc = -ENOMEM;
4224 }
4225 cifs_buf_release(pSMB);
4226 if (rc == -EAGAIN)
4227 goto QPathInfoRetry;
4228
4229 return rc;
4230}
4231
4232int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004233CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004234 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4235{
4236 struct smb_t2_qfi_req *pSMB = NULL;
4237 struct smb_t2_qfi_rsp *pSMBr = NULL;
4238 int rc = 0;
4239 int bytes_returned;
4240 __u16 params, byte_count;
4241
4242UnixQFileInfoRetry:
4243 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4244 (void **) &pSMBr);
4245 if (rc)
4246 return rc;
4247
4248 params = 2 /* level */ + 2 /* fid */;
4249 pSMB->t2.TotalDataCount = 0;
4250 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4251 /* BB find exact max data count below from sess structure BB */
4252 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4253 pSMB->t2.MaxSetupCount = 0;
4254 pSMB->t2.Reserved = 0;
4255 pSMB->t2.Flags = 0;
4256 pSMB->t2.Timeout = 0;
4257 pSMB->t2.Reserved2 = 0;
4258 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4259 Fid) - 4);
4260 pSMB->t2.DataCount = 0;
4261 pSMB->t2.DataOffset = 0;
4262 pSMB->t2.SetupCount = 1;
4263 pSMB->t2.Reserved3 = 0;
4264 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4265 byte_count = params + 1 /* pad */ ;
4266 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4267 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4268 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4269 pSMB->Pad = 0;
4270 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004271 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004272 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004273
4274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4275 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4276 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004277 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004278 } else { /* decode response */
4279 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4280
Jeff Layton820a8032011-05-04 08:05:26 -04004281 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004282 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 -05004283 rc = -EIO; /* bad smb */
4284 } else {
4285 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4286 memcpy((char *) pFindData,
4287 (char *) &pSMBr->hdr.Protocol +
4288 data_offset,
4289 sizeof(FILE_UNIX_BASIC_INFO));
4290 }
4291 }
4292
4293 cifs_buf_release(pSMB);
4294 if (rc == -EAGAIN)
4295 goto UnixQFileInfoRetry;
4296
4297 return rc;
4298}
4299
4300int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004301CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004303 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004304 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305{
4306/* SMB_QUERY_FILE_UNIX_BASIC */
4307 TRANSACTION2_QPI_REQ *pSMB = NULL;
4308 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4309 int rc = 0;
4310 int bytes_returned = 0;
4311 int name_len;
4312 __u16 params, byte_count;
4313
Joe Perchesf96637b2013-05-04 22:12:25 -05004314 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315UnixQPathInfoRetry:
4316 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4317 (void **) &pSMBr);
4318 if (rc)
4319 return rc;
4320
4321 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4322 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004323 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4324 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 name_len++; /* trailing null */
4326 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004327 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 name_len = strnlen(searchName, PATH_MAX);
4329 name_len++; /* trailing null */
4330 strncpy(pSMB->FileName, searchName, name_len);
4331 }
4332
Steve French50c2f752007-07-13 00:33:32 +00004333 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 pSMB->TotalDataCount = 0;
4335 pSMB->MaxParameterCount = cpu_to_le16(2);
4336 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004337 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 pSMB->MaxSetupCount = 0;
4339 pSMB->Reserved = 0;
4340 pSMB->Flags = 0;
4341 pSMB->Timeout = 0;
4342 pSMB->Reserved2 = 0;
4343 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004344 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 pSMB->DataCount = 0;
4346 pSMB->DataOffset = 0;
4347 pSMB->SetupCount = 1;
4348 pSMB->Reserved3 = 0;
4349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4350 byte_count = params + 1 /* pad */ ;
4351 pSMB->TotalParameterCount = cpu_to_le16(params);
4352 pSMB->ParameterCount = pSMB->TotalParameterCount;
4353 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4354 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004355 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 pSMB->ByteCount = cpu_to_le16(byte_count);
4357
4358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4360 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004361 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 } else { /* decode response */
4363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4364
Jeff Layton820a8032011-05-04 08:05:26 -04004365 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004366 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 -07004367 rc = -EIO; /* bad smb */
4368 } else {
4369 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4370 memcpy((char *) pFindData,
4371 (char *) &pSMBr->hdr.Protocol +
4372 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004373 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 }
4375 }
4376 cifs_buf_release(pSMB);
4377 if (rc == -EAGAIN)
4378 goto UnixQPathInfoRetry;
4379
4380 return rc;
4381}
4382
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383/* xid, tcon, searchName and codepage are input parms, rest are returned */
4384int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004385CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004386 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004387 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004388 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389{
4390/* level 257 SMB_ */
4391 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4392 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004393 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 int rc = 0;
4395 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004396 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004398 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399
Joe Perchesf96637b2013-05-04 22:12:25 -05004400 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401
4402findFirstRetry:
4403 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4404 (void **) &pSMBr);
4405 if (rc)
4406 return rc;
4407
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004408 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004409 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004410
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4412 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004413 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4414 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004415 /* We can not add the asterik earlier in case
4416 it got remapped to 0xF03A as if it were part of the
4417 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004419 if (msearch) {
4420 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4421 pSMB->FileName[name_len+1] = 0;
4422 pSMB->FileName[name_len+2] = '*';
4423 pSMB->FileName[name_len+3] = 0;
4424 name_len += 4; /* now the trailing null */
4425 /* null terminate just in case */
4426 pSMB->FileName[name_len] = 0;
4427 pSMB->FileName[name_len+1] = 0;
4428 name_len += 2;
4429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 } else { /* BB add check for overrun of SMB buf BB */
4431 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004433 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 free buffer exit; BB */
4435 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004436 if (msearch) {
4437 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4438 pSMB->FileName[name_len+1] = '*';
4439 pSMB->FileName[name_len+2] = 0;
4440 name_len += 3;
4441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 }
4443
4444 params = 12 + name_len /* includes null */ ;
4445 pSMB->TotalDataCount = 0; /* no EAs */
4446 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004447 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 pSMB->MaxSetupCount = 0;
4449 pSMB->Reserved = 0;
4450 pSMB->Flags = 0;
4451 pSMB->Timeout = 0;
4452 pSMB->Reserved2 = 0;
4453 byte_count = params + 1 /* pad */ ;
4454 pSMB->TotalParameterCount = cpu_to_le16(params);
4455 pSMB->ParameterCount = pSMB->TotalParameterCount;
4456 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004457 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4458 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 pSMB->DataCount = 0;
4460 pSMB->DataOffset = 0;
4461 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4462 pSMB->Reserved3 = 0;
4463 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4464 pSMB->SearchAttributes =
4465 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4466 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004467 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004468 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4470
4471 /* BB what should we set StorageType to? Does it matter? BB */
4472 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004473 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 pSMB->ByteCount = cpu_to_le16(byte_count);
4475
4476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4477 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004478 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479
Steve French88274812006-03-09 22:21:45 +00004480 if (rc) {/* BB add logic to retry regular search if Unix search
4481 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004483 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004484
Steve French88274812006-03-09 22:21:45 +00004485 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486
4487 /* BB eventually could optimize out free and realloc of buf */
4488 /* for this case */
4489 if (rc == -EAGAIN)
4490 goto findFirstRetry;
4491 } else { /* decode response */
4492 /* BB remember to free buffer if error BB */
4493 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004494 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004495 unsigned int lnoff;
4496
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004498 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 else
Steve French4b18f2a2008-04-29 00:06:05 +00004500 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501
4502 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004503 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004504 psrch_inf->srch_entries_start =
4505 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4508 le16_to_cpu(pSMBr->t2.ParameterOffset));
4509
Steve French790fe572007-07-07 19:25:05 +00004510 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004511 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 else
Steve French4b18f2a2008-04-29 00:06:05 +00004513 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514
Steve French50c2f752007-07-13 00:33:32 +00004515 psrch_inf->entries_in_buffer =
4516 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004517 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004519 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004520 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004521 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004522 psrch_inf->last_entry = NULL;
4523 return rc;
4524 }
4525
Steve French0752f152008-10-07 20:03:33 +00004526 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004527 lnoff;
4528
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004529 if (pnetfid)
4530 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 } else {
4532 cifs_buf_release(pSMB);
4533 }
4534 }
4535
4536 return rc;
4537}
4538
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004539int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4540 __u16 searchHandle, __u16 search_flags,
4541 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542{
4543 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4544 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004545 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 char *response_data;
4547 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004548 int bytes_returned;
4549 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 __u16 params, byte_count;
4551
Joe Perchesf96637b2013-05-04 22:12:25 -05004552 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553
Steve French4b18f2a2008-04-29 00:06:05 +00004554 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 return -ENOENT;
4556
4557 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4558 (void **) &pSMBr);
4559 if (rc)
4560 return rc;
4561
Steve French50c2f752007-07-13 00:33:32 +00004562 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 byte_count = 0;
4564 pSMB->TotalDataCount = 0; /* no EAs */
4565 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004566 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 pSMB->MaxSetupCount = 0;
4568 pSMB->Reserved = 0;
4569 pSMB->Flags = 0;
4570 pSMB->Timeout = 0;
4571 pSMB->Reserved2 = 0;
4572 pSMB->ParameterOffset = cpu_to_le16(
4573 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4574 pSMB->DataCount = 0;
4575 pSMB->DataOffset = 0;
4576 pSMB->SetupCount = 1;
4577 pSMB->Reserved3 = 0;
4578 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4579 pSMB->SearchHandle = searchHandle; /* always kept as le */
4580 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004581 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4583 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004584 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585
4586 name_len = psrch_inf->resume_name_len;
4587 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004588 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4590 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004591 /* 14 byte parm len above enough for 2 byte null terminator */
4592 pSMB->ResumeFileName[name_len] = 0;
4593 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 } else {
4595 rc = -EINVAL;
4596 goto FNext2_err_exit;
4597 }
4598 byte_count = params + 1 /* pad */ ;
4599 pSMB->TotalParameterCount = cpu_to_le16(params);
4600 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004601 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004603
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004606 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 if (rc) {
4608 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004609 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004610 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004611 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004613 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 } else { /* decode response */
4615 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004616
Steve French790fe572007-07-07 19:25:05 +00004617 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004618 unsigned int lnoff;
4619
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 /* BB fixme add lock for file (srch_info) struct here */
4621 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004622 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 else
Steve French4b18f2a2008-04-29 00:06:05 +00004624 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 response_data = (char *) &pSMBr->hdr.Protocol +
4626 le16_to_cpu(pSMBr->t2.ParameterOffset);
4627 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4628 response_data = (char *)&pSMBr->hdr.Protocol +
4629 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004630 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004631 cifs_small_buf_release(
4632 psrch_inf->ntwrk_buf_start);
4633 else
4634 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 psrch_inf->srch_entries_start = response_data;
4636 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004637 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004638 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004639 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 else
Steve French4b18f2a2008-04-29 00:06:05 +00004641 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004642 psrch_inf->entries_in_buffer =
4643 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 psrch_inf->index_of_last_entry +=
4645 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004646 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004647 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004648 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004649 psrch_inf->last_entry = NULL;
4650 return rc;
4651 } else
4652 psrch_inf->last_entry =
4653 psrch_inf->srch_entries_start + lnoff;
4654
Joe Perchesf96637b2013-05-04 22:12:25 -05004655/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4656 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
4658 /* BB fixme add unlock here */
4659 }
4660
4661 }
4662
4663 /* BB On error, should we leave previous search buf (and count and
4664 last entry fields) intact or free the previous one? */
4665
4666 /* Note: On -EAGAIN error only caller can retry on handle based calls
4667 since file handle passed in no longer valid */
4668FNext2_err_exit:
4669 if (rc != 0)
4670 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 return rc;
4672}
4673
4674int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004675CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004676 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677{
4678 int rc = 0;
4679 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
Joe Perchesf96637b2013-05-04 22:12:25 -05004681 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4683
4684 /* no sense returning error if session restarted
4685 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004686 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 return 0;
4688 if (rc)
4689 return rc;
4690
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 pSMB->FileID = searchHandle;
4692 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004693 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004694 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004695 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004696
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004697 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698
4699 /* Since session is dead, search handle closed on server already */
4700 if (rc == -EAGAIN)
4701 rc = 0;
4702
4703 return rc;
4704}
4705
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004707CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004708 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004709 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710{
4711 int rc = 0;
4712 TRANSACTION2_QPI_REQ *pSMB = NULL;
4713 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4714 int name_len, bytes_returned;
4715 __u16 params, byte_count;
4716
Joe Perchesf96637b2013-05-04 22:12:25 -05004717 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004718 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004719 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720
4721GetInodeNumberRetry:
4722 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004723 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 if (rc)
4725 return rc;
4726
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4728 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004729 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004730 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004731 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 name_len++; /* trailing null */
4733 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004734 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004735 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004737 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 }
4739
4740 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4741 pSMB->TotalDataCount = 0;
4742 pSMB->MaxParameterCount = cpu_to_le16(2);
4743 /* BB find exact max data count below from sess structure BB */
4744 pSMB->MaxDataCount = cpu_to_le16(4000);
4745 pSMB->MaxSetupCount = 0;
4746 pSMB->Reserved = 0;
4747 pSMB->Flags = 0;
4748 pSMB->Timeout = 0;
4749 pSMB->Reserved2 = 0;
4750 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004751 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 pSMB->DataCount = 0;
4753 pSMB->DataOffset = 0;
4754 pSMB->SetupCount = 1;
4755 pSMB->Reserved3 = 0;
4756 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4757 byte_count = params + 1 /* pad */ ;
4758 pSMB->TotalParameterCount = cpu_to_le16(params);
4759 pSMB->ParameterCount = pSMB->TotalParameterCount;
4760 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4761 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004762 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 pSMB->ByteCount = cpu_to_le16(byte_count);
4764
4765 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4766 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4767 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004768 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 } else {
4770 /* decode response */
4771 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004773 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 /* If rc should we check for EOPNOSUPP and
4775 disable the srvino flag? or in caller? */
4776 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004777 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4779 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004780 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004782 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004783 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 rc = -EIO;
4785 goto GetInodeNumOut;
4786 }
4787 pfinfo = (struct file_internal_info *)
4788 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004789 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 }
4791 }
4792GetInodeNumOut:
4793 cifs_buf_release(pSMB);
4794 if (rc == -EAGAIN)
4795 goto GetInodeNumberRetry;
4796 return rc;
4797}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798
Igor Mammedovfec45852008-05-16 13:06:30 +04004799/* parses DFS refferal V3 structure
4800 * caller is responsible for freeing target_nodes
4801 * returns:
4802 * on success - 0
4803 * on failure - errno
4804 */
4805static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004806parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004807 unsigned int *num_of_nodes,
4808 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004809 const struct nls_table *nls_codepage, int remap,
4810 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004811{
4812 int i, rc = 0;
4813 char *data_end;
4814 bool is_unicode;
4815 struct dfs_referral_level_3 *ref;
4816
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004817 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4818 is_unicode = true;
4819 else
4820 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004821 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4822
4823 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004824 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4825 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004826 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004827 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004828 }
4829
4830 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004831 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004832 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4833 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004834 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004835 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004836 }
4837
4838 /* get the upper boundary of the resp buffer */
4839 data_end = (char *)(&(pSMBr->PathConsumed)) +
4840 le16_to_cpu(pSMBr->t2.DataCount);
4841
Joe Perchesf96637b2013-05-04 22:12:25 -05004842 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4843 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004844
Joe Perchesf96637b2013-05-04 22:12:25 -05004845 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4846 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004847 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004848 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004849 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004850 }
4851
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004852 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004853 for (i = 0; i < *num_of_nodes; i++) {
4854 char *temp;
4855 int max_len;
4856 struct dfs_info3_param *node = (*target_nodes)+i;
4857
Steve French0e0d2cf2009-05-01 05:27:32 +00004858 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004859 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004860 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4861 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004862 if (tmp == NULL) {
4863 rc = -ENOMEM;
4864 goto parse_DFS_referrals_exit;
4865 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004866 cifsConvertToUTF16((__le16 *) tmp, searchName,
4867 PATH_MAX, nls_codepage, remap);
4868 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004869 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004870 nls_codepage);
4871 kfree(tmp);
4872 } else
4873 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4874
Igor Mammedovfec45852008-05-16 13:06:30 +04004875 node->server_type = le16_to_cpu(ref->ServerType);
4876 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4877
4878 /* copy DfsPath */
4879 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4880 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004881 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4882 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004883 if (!node->path_name) {
4884 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004885 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004886 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004887
4888 /* copy link target UNC */
4889 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4890 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004891 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4892 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004893 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004894 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004895 goto parse_DFS_referrals_exit;
4896 }
4897
4898 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004899 }
4900
Steve Frencha1fe78f2008-05-16 18:48:38 +00004901parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004902 if (rc) {
4903 free_dfs_info_array(*target_nodes, *num_of_nodes);
4904 *target_nodes = NULL;
4905 *num_of_nodes = 0;
4906 }
4907 return rc;
4908}
4909
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004911CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004912 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004913 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004914 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915{
4916/* TRANS2_GET_DFS_REFERRAL */
4917 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4918 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 int rc = 0;
4920 int bytes_returned;
4921 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004923 *num_of_nodes = 0;
4924 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925
Joe Perchesf96637b2013-05-04 22:12:25 -05004926 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 if (ses == NULL)
4928 return -ENODEV;
4929getDFSRetry:
4930 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4931 (void **) &pSMBr);
4932 if (rc)
4933 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004934
4935 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004936 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004937 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 pSMB->hdr.Tid = ses->ipc_tid;
4939 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004940 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004942 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944
4945 if (ses->capabilities & CAP_UNICODE) {
4946 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4947 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004948 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004949 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004950 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 name_len++; /* trailing null */
4952 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004953 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004954 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004956 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 }
4958
Dan Carpenter65c3b202015-04-30 17:30:24 +03004959 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004960 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004961
Steve French50c2f752007-07-13 00:33:32 +00004962 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004963
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 params = 2 /* level */ + name_len /*includes null */ ;
4965 pSMB->TotalDataCount = 0;
4966 pSMB->DataCount = 0;
4967 pSMB->DataOffset = 0;
4968 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004969 /* BB find exact max SMB PDU from sess structure BB */
4970 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 pSMB->MaxSetupCount = 0;
4972 pSMB->Reserved = 0;
4973 pSMB->Flags = 0;
4974 pSMB->Timeout = 0;
4975 pSMB->Reserved2 = 0;
4976 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004977 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 pSMB->SetupCount = 1;
4979 pSMB->Reserved3 = 0;
4980 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4981 byte_count = params + 3 /* pad */ ;
4982 pSMB->ParameterCount = cpu_to_le16(params);
4983 pSMB->TotalParameterCount = pSMB->ParameterCount;
4984 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004985 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 pSMB->ByteCount = cpu_to_le16(byte_count);
4987
4988 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4990 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004991 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004992 goto GetDFSRefExit;
4993 }
4994 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004996 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004997 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004998 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004999 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 }
Igor Mammedovfec45852008-05-16 13:06:30 +04005001
Joe Perchesf96637b2013-05-04 22:12:25 -05005002 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
5003 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04005004
5005 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00005006 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04005007 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04005008 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04005009
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00005011 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012
5013 if (rc == -EAGAIN)
5014 goto getDFSRetry;
5015
5016 return rc;
5017}
5018
Steve French20962432005-09-21 22:05:57 -07005019/* Query File System Info such as free space to old servers such as Win 9x */
5020int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005021SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5022 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005023{
5024/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5025 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5026 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5027 FILE_SYSTEM_ALLOC_INFO *response_data;
5028 int rc = 0;
5029 int bytes_returned = 0;
5030 __u16 params, byte_count;
5031
Joe Perchesf96637b2013-05-04 22:12:25 -05005032 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005033oldQFSInfoRetry:
5034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5035 (void **) &pSMBr);
5036 if (rc)
5037 return rc;
Steve French20962432005-09-21 22:05:57 -07005038
5039 params = 2; /* level */
5040 pSMB->TotalDataCount = 0;
5041 pSMB->MaxParameterCount = cpu_to_le16(2);
5042 pSMB->MaxDataCount = cpu_to_le16(1000);
5043 pSMB->MaxSetupCount = 0;
5044 pSMB->Reserved = 0;
5045 pSMB->Flags = 0;
5046 pSMB->Timeout = 0;
5047 pSMB->Reserved2 = 0;
5048 byte_count = params + 1 /* pad */ ;
5049 pSMB->TotalParameterCount = cpu_to_le16(params);
5050 pSMB->ParameterCount = pSMB->TotalParameterCount;
5051 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5052 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5053 pSMB->DataCount = 0;
5054 pSMB->DataOffset = 0;
5055 pSMB->SetupCount = 1;
5056 pSMB->Reserved3 = 0;
5057 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5058 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005059 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005060 pSMB->ByteCount = cpu_to_le16(byte_count);
5061
5062 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5063 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5064 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005065 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005066 } else { /* decode response */
5067 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5068
Jeff Layton820a8032011-05-04 08:05:26 -04005069 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005070 rc = -EIO; /* bad smb */
5071 else {
5072 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005073 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005074 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005075
Steve French50c2f752007-07-13 00:33:32 +00005076 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005077 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5078 FSData->f_bsize =
5079 le16_to_cpu(response_data->BytesPerSector) *
5080 le32_to_cpu(response_data->
5081 SectorsPerAllocationUnit);
5082 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005083 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005084 FSData->f_bfree = FSData->f_bavail =
5085 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005086 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5087 (unsigned long long)FSData->f_blocks,
5088 (unsigned long long)FSData->f_bfree,
5089 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005090 }
5091 }
5092 cifs_buf_release(pSMB);
5093
5094 if (rc == -EAGAIN)
5095 goto oldQFSInfoRetry;
5096
5097 return rc;
5098}
5099
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005101CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5102 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103{
5104/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5105 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5106 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5107 FILE_SYSTEM_INFO *response_data;
5108 int rc = 0;
5109 int bytes_returned = 0;
5110 __u16 params, byte_count;
5111
Joe Perchesf96637b2013-05-04 22:12:25 -05005112 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113QFSInfoRetry:
5114 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5115 (void **) &pSMBr);
5116 if (rc)
5117 return rc;
5118
5119 params = 2; /* level */
5120 pSMB->TotalDataCount = 0;
5121 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005122 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 pSMB->MaxSetupCount = 0;
5124 pSMB->Reserved = 0;
5125 pSMB->Flags = 0;
5126 pSMB->Timeout = 0;
5127 pSMB->Reserved2 = 0;
5128 byte_count = params + 1 /* pad */ ;
5129 pSMB->TotalParameterCount = cpu_to_le16(params);
5130 pSMB->ParameterCount = pSMB->TotalParameterCount;
5131 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005132 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 pSMB->DataCount = 0;
5134 pSMB->DataOffset = 0;
5135 pSMB->SetupCount = 1;
5136 pSMB->Reserved3 = 0;
5137 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5138 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005139 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 pSMB->ByteCount = cpu_to_le16(byte_count);
5141
5142 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5143 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5144 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005145 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005147 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148
Jeff Layton820a8032011-05-04 08:05:26 -04005149 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 rc = -EIO; /* bad smb */
5151 else {
5152 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153
5154 response_data =
5155 (FILE_SYSTEM_INFO
5156 *) (((char *) &pSMBr->hdr.Protocol) +
5157 data_offset);
5158 FSData->f_bsize =
5159 le32_to_cpu(response_data->BytesPerSector) *
5160 le32_to_cpu(response_data->
5161 SectorsPerAllocationUnit);
5162 FSData->f_blocks =
5163 le64_to_cpu(response_data->TotalAllocationUnits);
5164 FSData->f_bfree = FSData->f_bavail =
5165 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005166 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5167 (unsigned long long)FSData->f_blocks,
5168 (unsigned long long)FSData->f_bfree,
5169 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 }
5171 }
5172 cifs_buf_release(pSMB);
5173
5174 if (rc == -EAGAIN)
5175 goto QFSInfoRetry;
5176
5177 return rc;
5178}
5179
5180int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005181CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182{
5183/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5184 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5185 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5186 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5187 int rc = 0;
5188 int bytes_returned = 0;
5189 __u16 params, byte_count;
5190
Joe Perchesf96637b2013-05-04 22:12:25 -05005191 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192QFSAttributeRetry:
5193 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5194 (void **) &pSMBr);
5195 if (rc)
5196 return rc;
5197
5198 params = 2; /* level */
5199 pSMB->TotalDataCount = 0;
5200 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005201 /* BB find exact max SMB PDU from sess structure BB */
5202 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 pSMB->MaxSetupCount = 0;
5204 pSMB->Reserved = 0;
5205 pSMB->Flags = 0;
5206 pSMB->Timeout = 0;
5207 pSMB->Reserved2 = 0;
5208 byte_count = params + 1 /* pad */ ;
5209 pSMB->TotalParameterCount = cpu_to_le16(params);
5210 pSMB->ParameterCount = pSMB->TotalParameterCount;
5211 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005212 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 pSMB->DataCount = 0;
5214 pSMB->DataOffset = 0;
5215 pSMB->SetupCount = 1;
5216 pSMB->Reserved3 = 0;
5217 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5218 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005219 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 pSMB->ByteCount = cpu_to_le16(byte_count);
5221
5222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5224 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005225 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 } else { /* decode response */
5227 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5228
Jeff Layton820a8032011-05-04 08:05:26 -04005229 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005230 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 rc = -EIO; /* bad smb */
5232 } else {
5233 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5234 response_data =
5235 (FILE_SYSTEM_ATTRIBUTE_INFO
5236 *) (((char *) &pSMBr->hdr.Protocol) +
5237 data_offset);
5238 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005239 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 }
5241 }
5242 cifs_buf_release(pSMB);
5243
5244 if (rc == -EAGAIN)
5245 goto QFSAttributeRetry;
5246
5247 return rc;
5248}
5249
5250int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005251CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252{
5253/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5254 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5255 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5256 FILE_SYSTEM_DEVICE_INFO *response_data;
5257 int rc = 0;
5258 int bytes_returned = 0;
5259 __u16 params, byte_count;
5260
Joe Perchesf96637b2013-05-04 22:12:25 -05005261 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262QFSDeviceRetry:
5263 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5264 (void **) &pSMBr);
5265 if (rc)
5266 return rc;
5267
5268 params = 2; /* level */
5269 pSMB->TotalDataCount = 0;
5270 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005271 /* BB find exact max SMB PDU from sess structure BB */
5272 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 pSMB->MaxSetupCount = 0;
5274 pSMB->Reserved = 0;
5275 pSMB->Flags = 0;
5276 pSMB->Timeout = 0;
5277 pSMB->Reserved2 = 0;
5278 byte_count = params + 1 /* pad */ ;
5279 pSMB->TotalParameterCount = cpu_to_le16(params);
5280 pSMB->ParameterCount = pSMB->TotalParameterCount;
5281 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005282 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283
5284 pSMB->DataCount = 0;
5285 pSMB->DataOffset = 0;
5286 pSMB->SetupCount = 1;
5287 pSMB->Reserved3 = 0;
5288 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5289 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005290 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 pSMB->ByteCount = cpu_to_le16(byte_count);
5292
5293 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5294 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5295 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005296 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 } else { /* decode response */
5298 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5299
Jeff Layton820a8032011-05-04 08:05:26 -04005300 if (rc || get_bcc(&pSMBr->hdr) <
5301 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 rc = -EIO; /* bad smb */
5303 else {
5304 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5305 response_data =
Steve French737b7582005-04-28 22:41:06 -07005306 (FILE_SYSTEM_DEVICE_INFO *)
5307 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 data_offset);
5309 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005310 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 }
5312 }
5313 cifs_buf_release(pSMB);
5314
5315 if (rc == -EAGAIN)
5316 goto QFSDeviceRetry;
5317
5318 return rc;
5319}
5320
5321int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005322CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323{
5324/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5325 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5326 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5327 FILE_SYSTEM_UNIX_INFO *response_data;
5328 int rc = 0;
5329 int bytes_returned = 0;
5330 __u16 params, byte_count;
5331
Joe Perchesf96637b2013-05-04 22:12:25 -05005332 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005334 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5335 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 if (rc)
5337 return rc;
5338
5339 params = 2; /* level */
5340 pSMB->TotalDataCount = 0;
5341 pSMB->DataCount = 0;
5342 pSMB->DataOffset = 0;
5343 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005344 /* BB find exact max SMB PDU from sess structure BB */
5345 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 pSMB->MaxSetupCount = 0;
5347 pSMB->Reserved = 0;
5348 pSMB->Flags = 0;
5349 pSMB->Timeout = 0;
5350 pSMB->Reserved2 = 0;
5351 byte_count = params + 1 /* pad */ ;
5352 pSMB->ParameterCount = cpu_to_le16(params);
5353 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005354 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5355 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 pSMB->SetupCount = 1;
5357 pSMB->Reserved3 = 0;
5358 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5359 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005360 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 pSMB->ByteCount = cpu_to_le16(byte_count);
5362
5363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5365 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005366 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 } else { /* decode response */
5368 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5369
Jeff Layton820a8032011-05-04 08:05:26 -04005370 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 rc = -EIO; /* bad smb */
5372 } else {
5373 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5374 response_data =
5375 (FILE_SYSTEM_UNIX_INFO
5376 *) (((char *) &pSMBr->hdr.Protocol) +
5377 data_offset);
5378 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005379 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 }
5381 }
5382 cifs_buf_release(pSMB);
5383
5384 if (rc == -EAGAIN)
5385 goto QFSUnixRetry;
5386
5387
5388 return rc;
5389}
5390
Jeremy Allisonac670552005-06-22 17:26:35 -07005391int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005392CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005393{
5394/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5395 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5396 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5397 int rc = 0;
5398 int bytes_returned = 0;
5399 __u16 params, param_offset, offset, byte_count;
5400
Joe Perchesf96637b2013-05-04 22:12:25 -05005401 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005402SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005403 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005404 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5405 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005406 if (rc)
5407 return rc;
5408
5409 params = 4; /* 2 bytes zero followed by info level. */
5410 pSMB->MaxSetupCount = 0;
5411 pSMB->Reserved = 0;
5412 pSMB->Flags = 0;
5413 pSMB->Timeout = 0;
5414 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005415 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5416 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005417 offset = param_offset + params;
5418
5419 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005420 /* BB find exact max SMB PDU from sess structure BB */
5421 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005422 pSMB->SetupCount = 1;
5423 pSMB->Reserved3 = 0;
5424 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5425 byte_count = 1 /* pad */ + params + 12;
5426
5427 pSMB->DataCount = cpu_to_le16(12);
5428 pSMB->ParameterCount = cpu_to_le16(params);
5429 pSMB->TotalDataCount = pSMB->DataCount;
5430 pSMB->TotalParameterCount = pSMB->ParameterCount;
5431 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5432 pSMB->DataOffset = cpu_to_le16(offset);
5433
5434 /* Params. */
5435 pSMB->FileNum = 0;
5436 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5437
5438 /* Data. */
5439 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5440 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5441 pSMB->ClientUnixCap = cpu_to_le64(cap);
5442
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005443 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005444 pSMB->ByteCount = cpu_to_le16(byte_count);
5445
5446 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5447 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5448 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005449 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005450 } else { /* decode response */
5451 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005452 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005453 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005454 }
5455 cifs_buf_release(pSMB);
5456
5457 if (rc == -EAGAIN)
5458 goto SETFSUnixRetry;
5459
5460 return rc;
5461}
5462
5463
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
5465int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005466CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005467 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468{
5469/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5470 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5471 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5472 FILE_SYSTEM_POSIX_INFO *response_data;
5473 int rc = 0;
5474 int bytes_returned = 0;
5475 __u16 params, byte_count;
5476
Joe Perchesf96637b2013-05-04 22:12:25 -05005477 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478QFSPosixRetry:
5479 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5480 (void **) &pSMBr);
5481 if (rc)
5482 return rc;
5483
5484 params = 2; /* level */
5485 pSMB->TotalDataCount = 0;
5486 pSMB->DataCount = 0;
5487 pSMB->DataOffset = 0;
5488 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005489 /* BB find exact max SMB PDU from sess structure BB */
5490 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 pSMB->MaxSetupCount = 0;
5492 pSMB->Reserved = 0;
5493 pSMB->Flags = 0;
5494 pSMB->Timeout = 0;
5495 pSMB->Reserved2 = 0;
5496 byte_count = params + 1 /* pad */ ;
5497 pSMB->ParameterCount = cpu_to_le16(params);
5498 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005499 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5500 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 pSMB->SetupCount = 1;
5502 pSMB->Reserved3 = 0;
5503 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5504 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005505 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 pSMB->ByteCount = cpu_to_le16(byte_count);
5507
5508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5510 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005511 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 } else { /* decode response */
5513 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5514
Jeff Layton820a8032011-05-04 08:05:26 -04005515 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 rc = -EIO; /* bad smb */
5517 } else {
5518 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5519 response_data =
5520 (FILE_SYSTEM_POSIX_INFO
5521 *) (((char *) &pSMBr->hdr.Protocol) +
5522 data_offset);
5523 FSData->f_bsize =
5524 le32_to_cpu(response_data->BlockSize);
5525 FSData->f_blocks =
5526 le64_to_cpu(response_data->TotalBlocks);
5527 FSData->f_bfree =
5528 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005529 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 FSData->f_bavail = FSData->f_bfree;
5531 } else {
5532 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005533 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 }
Steve French790fe572007-07-07 19:25:05 +00005535 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005537 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005538 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005540 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 }
5542 }
5543 cifs_buf_release(pSMB);
5544
5545 if (rc == -EAGAIN)
5546 goto QFSPosixRetry;
5547
5548 return rc;
5549}
5550
5551
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005552/*
5553 * We can not use write of zero bytes trick to set file size due to need for
5554 * large file support. Also note that this SetPathInfo is preferred to
5555 * SetFileInfo based method in next routine which is only needed to work around
5556 * a sharing violation bugin Samba which this routine can run into.
5557 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005559CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005560 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5561 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562{
5563 struct smb_com_transaction2_spi_req *pSMB = NULL;
5564 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5565 struct file_end_of_file_info *parm_data;
5566 int name_len;
5567 int rc = 0;
5568 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005569 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005570
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 __u16 params, byte_count, data_count, param_offset, offset;
5572
Joe Perchesf96637b2013-05-04 22:12:25 -05005573 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574SetEOFRetry:
5575 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5576 (void **) &pSMBr);
5577 if (rc)
5578 return rc;
5579
5580 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5581 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005582 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5583 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 name_len++; /* trailing null */
5585 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005586 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005587 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005589 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 }
5591 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005592 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005594 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 pSMB->MaxSetupCount = 0;
5596 pSMB->Reserved = 0;
5597 pSMB->Flags = 0;
5598 pSMB->Timeout = 0;
5599 pSMB->Reserved2 = 0;
5600 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005601 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005603 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005604 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5605 pSMB->InformationLevel =
5606 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5607 else
5608 pSMB->InformationLevel =
5609 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5610 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5612 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005613 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 else
5615 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005616 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 }
5618
5619 parm_data =
5620 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5621 offset);
5622 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5623 pSMB->DataOffset = cpu_to_le16(offset);
5624 pSMB->SetupCount = 1;
5625 pSMB->Reserved3 = 0;
5626 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5627 byte_count = 3 /* pad */ + params + data_count;
5628 pSMB->DataCount = cpu_to_le16(data_count);
5629 pSMB->TotalDataCount = pSMB->DataCount;
5630 pSMB->ParameterCount = cpu_to_le16(params);
5631 pSMB->TotalParameterCount = pSMB->ParameterCount;
5632 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005633 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 parm_data->FileSize = cpu_to_le64(size);
5635 pSMB->ByteCount = cpu_to_le16(byte_count);
5636 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5637 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005638 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005639 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
5641 cifs_buf_release(pSMB);
5642
5643 if (rc == -EAGAIN)
5644 goto SetEOFRetry;
5645
5646 return rc;
5647}
5648
5649int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005650CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5651 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652{
5653 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 struct file_end_of_file_info *parm_data;
5655 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 __u16 params, param_offset, offset, byte_count, count;
5657
Joe Perchesf96637b2013-05-04 22:12:25 -05005658 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5659 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005660 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5661
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 if (rc)
5663 return rc;
5664
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005665 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5666 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005667
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 params = 6;
5669 pSMB->MaxSetupCount = 0;
5670 pSMB->Reserved = 0;
5671 pSMB->Flags = 0;
5672 pSMB->Timeout = 0;
5673 pSMB->Reserved2 = 0;
5674 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5675 offset = param_offset + params;
5676
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 count = sizeof(struct file_end_of_file_info);
5678 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005679 /* BB find exact max SMB PDU from sess structure BB */
5680 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 pSMB->SetupCount = 1;
5682 pSMB->Reserved3 = 0;
5683 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5684 byte_count = 3 /* pad */ + params + count;
5685 pSMB->DataCount = cpu_to_le16(count);
5686 pSMB->ParameterCount = cpu_to_le16(params);
5687 pSMB->TotalDataCount = pSMB->DataCount;
5688 pSMB->TotalParameterCount = pSMB->ParameterCount;
5689 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5690 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005691 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5692 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 pSMB->DataOffset = cpu_to_le16(offset);
5694 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005695 pSMB->Fid = cfile->fid.netfid;
5696 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5698 pSMB->InformationLevel =
5699 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5700 else
5701 pSMB->InformationLevel =
5702 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005703 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5705 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005706 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 else
5708 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005709 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 }
5711 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005712 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005714 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005716 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5717 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 }
5719
Steve French50c2f752007-07-13 00:33:32 +00005720 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 since file handle passed in no longer valid */
5722
5723 return rc;
5724}
5725
Steve French50c2f752007-07-13 00:33:32 +00005726/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 an open handle, rather than by pathname - this is awkward due to
5728 potential access conflicts on the open, but it is unavoidable for these
5729 old servers since the only other choice is to go from 100 nanosecond DCE
5730 time and resort to the original setpathinfo level which takes the ancient
5731 DOS time format with 2 second granularity */
5732int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005733CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005734 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735{
5736 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 char *data_offset;
5738 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 __u16 params, param_offset, offset, byte_count, count;
5740
Joe Perchesf96637b2013-05-04 22:12:25 -05005741 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005742 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5743
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744 if (rc)
5745 return rc;
5746
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005747 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5748 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005749
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 params = 6;
5751 pSMB->MaxSetupCount = 0;
5752 pSMB->Reserved = 0;
5753 pSMB->Flags = 0;
5754 pSMB->Timeout = 0;
5755 pSMB->Reserved2 = 0;
5756 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5757 offset = param_offset + params;
5758
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005759 data_offset = (char *)pSMB +
5760 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761
Steve French26f57362007-08-30 22:09:15 +00005762 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005764 /* BB find max SMB PDU from sess */
5765 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 pSMB->SetupCount = 1;
5767 pSMB->Reserved3 = 0;
5768 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5769 byte_count = 3 /* pad */ + params + count;
5770 pSMB->DataCount = cpu_to_le16(count);
5771 pSMB->ParameterCount = cpu_to_le16(params);
5772 pSMB->TotalDataCount = pSMB->DataCount;
5773 pSMB->TotalParameterCount = pSMB->ParameterCount;
5774 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5775 pSMB->DataOffset = cpu_to_le16(offset);
5776 pSMB->Fid = fid;
5777 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5778 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5779 else
5780 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5781 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005782 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005784 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005785 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005786 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005787 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5788 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
Steve French50c2f752007-07-13 00:33:32 +00005790 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 since file handle passed in no longer valid */
5792
5793 return rc;
5794}
5795
Jeff Layton6d22f092008-09-23 11:48:35 -04005796int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005797CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005798 bool delete_file, __u16 fid, __u32 pid_of_opener)
5799{
5800 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5801 char *data_offset;
5802 int rc = 0;
5803 __u16 params, param_offset, offset, byte_count, count;
5804
Joe Perchesf96637b2013-05-04 22:12:25 -05005805 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005806 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5807
5808 if (rc)
5809 return rc;
5810
5811 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5812 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5813
5814 params = 6;
5815 pSMB->MaxSetupCount = 0;
5816 pSMB->Reserved = 0;
5817 pSMB->Flags = 0;
5818 pSMB->Timeout = 0;
5819 pSMB->Reserved2 = 0;
5820 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5821 offset = param_offset + params;
5822
5823 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5824
5825 count = 1;
5826 pSMB->MaxParameterCount = cpu_to_le16(2);
5827 /* BB find max SMB PDU from sess */
5828 pSMB->MaxDataCount = cpu_to_le16(1000);
5829 pSMB->SetupCount = 1;
5830 pSMB->Reserved3 = 0;
5831 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5832 byte_count = 3 /* pad */ + params + count;
5833 pSMB->DataCount = cpu_to_le16(count);
5834 pSMB->ParameterCount = cpu_to_le16(params);
5835 pSMB->TotalDataCount = pSMB->DataCount;
5836 pSMB->TotalParameterCount = pSMB->ParameterCount;
5837 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5838 pSMB->DataOffset = cpu_to_le16(offset);
5839 pSMB->Fid = fid;
5840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5841 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005842 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005843 pSMB->ByteCount = cpu_to_le16(byte_count);
5844 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005845 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005846 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005847 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005848
5849 return rc;
5850}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851
5852int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005853CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005854 const char *fileName, const FILE_BASIC_INFO *data,
5855 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856{
5857 TRANSACTION2_SPI_REQ *pSMB = NULL;
5858 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5859 int name_len;
5860 int rc = 0;
5861 int bytes_returned = 0;
5862 char *data_offset;
5863 __u16 params, param_offset, offset, byte_count, count;
5864
Joe Perchesf96637b2013-05-04 22:12:25 -05005865 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866
5867SetTimesRetry:
5868 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5869 (void **) &pSMBr);
5870 if (rc)
5871 return rc;
5872
5873 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5874 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005875 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5876 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 name_len++; /* trailing null */
5878 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005879 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 name_len = strnlen(fileName, PATH_MAX);
5881 name_len++; /* trailing null */
5882 strncpy(pSMB->FileName, fileName, name_len);
5883 }
5884
5885 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005886 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005888 /* BB find max SMB PDU from sess structure BB */
5889 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 pSMB->MaxSetupCount = 0;
5891 pSMB->Reserved = 0;
5892 pSMB->Flags = 0;
5893 pSMB->Timeout = 0;
5894 pSMB->Reserved2 = 0;
5895 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005896 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 offset = param_offset + params;
5898 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5899 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5900 pSMB->DataOffset = cpu_to_le16(offset);
5901 pSMB->SetupCount = 1;
5902 pSMB->Reserved3 = 0;
5903 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5904 byte_count = 3 /* pad */ + params + count;
5905
5906 pSMB->DataCount = cpu_to_le16(count);
5907 pSMB->ParameterCount = cpu_to_le16(params);
5908 pSMB->TotalDataCount = pSMB->DataCount;
5909 pSMB->TotalParameterCount = pSMB->ParameterCount;
5910 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5911 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5912 else
5913 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5914 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005915 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005916 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 pSMB->ByteCount = cpu_to_le16(byte_count);
5918 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5919 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005920 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005921 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
5923 cifs_buf_release(pSMB);
5924
5925 if (rc == -EAGAIN)
5926 goto SetTimesRetry;
5927
5928 return rc;
5929}
5930
5931/* Can not be used to set time stamps yet (due to old DOS time format) */
5932/* Can be used to set attributes */
5933#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5934 handling it anyway and NT4 was what we thought it would be needed for
5935 Do not delete it until we prove whether needed for Win9x though */
5936int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005937CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938 __u16 dos_attrs, const struct nls_table *nls_codepage)
5939{
5940 SETATTR_REQ *pSMB = NULL;
5941 SETATTR_RSP *pSMBr = NULL;
5942 int rc = 0;
5943 int bytes_returned;
5944 int name_len;
5945
Joe Perchesf96637b2013-05-04 22:12:25 -05005946 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947
5948SetAttrLgcyRetry:
5949 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5950 (void **) &pSMBr);
5951 if (rc)
5952 return rc;
5953
5954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5955 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005956 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5957 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 name_len++; /* trailing null */
5959 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005960 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 name_len = strnlen(fileName, PATH_MAX);
5962 name_len++; /* trailing null */
5963 strncpy(pSMB->fileName, fileName, name_len);
5964 }
5965 pSMB->attr = cpu_to_le16(dos_attrs);
5966 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005967 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005971 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005972 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973
5974 cifs_buf_release(pSMB);
5975
5976 if (rc == -EAGAIN)
5977 goto SetAttrLgcyRetry;
5978
5979 return rc;
5980}
5981#endif /* temporarily unneeded SetAttr legacy function */
5982
Jeff Layton654cf142009-07-09 20:02:49 -04005983static void
5984cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5985 const struct cifs_unix_set_info_args *args)
5986{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005987 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005988 u64 mode = args->mode;
5989
Eric W. Biederman49418b22013-02-06 00:57:56 -08005990 if (uid_valid(args->uid))
5991 uid = from_kuid(&init_user_ns, args->uid);
5992 if (gid_valid(args->gid))
5993 gid = from_kgid(&init_user_ns, args->gid);
5994
Jeff Layton654cf142009-07-09 20:02:49 -04005995 /*
5996 * Samba server ignores set of file size to zero due to bugs in some
5997 * older clients, but we should be precise - we use SetFileSize to
5998 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005999 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04006000 * zero instead of -1 here
6001 */
6002 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
6003 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
6004 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
6005 data_offset->LastAccessTime = cpu_to_le64(args->atime);
6006 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08006007 data_offset->Uid = cpu_to_le64(uid);
6008 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04006009 /* better to leave device as zero when it is */
6010 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
6011 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
6012 data_offset->Permissions = cpu_to_le64(mode);
6013
6014 if (S_ISREG(mode))
6015 data_offset->Type = cpu_to_le32(UNIX_FILE);
6016 else if (S_ISDIR(mode))
6017 data_offset->Type = cpu_to_le32(UNIX_DIR);
6018 else if (S_ISLNK(mode))
6019 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6020 else if (S_ISCHR(mode))
6021 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6022 else if (S_ISBLK(mode))
6023 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6024 else if (S_ISFIFO(mode))
6025 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6026 else if (S_ISSOCK(mode))
6027 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6028}
6029
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006031CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006032 const struct cifs_unix_set_info_args *args,
6033 u16 fid, u32 pid_of_opener)
6034{
6035 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006036 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006037 int rc = 0;
6038 u16 params, param_offset, offset, byte_count, count;
6039
Joe Perchesf96637b2013-05-04 22:12:25 -05006040 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006041 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6042
6043 if (rc)
6044 return rc;
6045
6046 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6047 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6048
6049 params = 6;
6050 pSMB->MaxSetupCount = 0;
6051 pSMB->Reserved = 0;
6052 pSMB->Flags = 0;
6053 pSMB->Timeout = 0;
6054 pSMB->Reserved2 = 0;
6055 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6056 offset = param_offset + params;
6057
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006058 data_offset = (char *)pSMB +
6059 offsetof(struct smb_hdr, Protocol) + offset;
6060
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006061 count = sizeof(FILE_UNIX_BASIC_INFO);
6062
6063 pSMB->MaxParameterCount = cpu_to_le16(2);
6064 /* BB find max SMB PDU from sess */
6065 pSMB->MaxDataCount = cpu_to_le16(1000);
6066 pSMB->SetupCount = 1;
6067 pSMB->Reserved3 = 0;
6068 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6069 byte_count = 3 /* pad */ + params + count;
6070 pSMB->DataCount = cpu_to_le16(count);
6071 pSMB->ParameterCount = cpu_to_le16(params);
6072 pSMB->TotalDataCount = pSMB->DataCount;
6073 pSMB->TotalParameterCount = pSMB->ParameterCount;
6074 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6075 pSMB->DataOffset = cpu_to_le16(offset);
6076 pSMB->Fid = fid;
6077 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6078 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006079 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006080 pSMB->ByteCount = cpu_to_le16(byte_count);
6081
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006082 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006083
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006084 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006085 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006086 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6087 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006088
6089 /* Note: On -EAGAIN error only caller can retry on handle based calls
6090 since file handle passed in no longer valid */
6091
6092 return rc;
6093}
6094
6095int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006096CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006097 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006098 const struct cifs_unix_set_info_args *args,
6099 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100{
6101 TRANSACTION2_SPI_REQ *pSMB = NULL;
6102 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6103 int name_len;
6104 int rc = 0;
6105 int bytes_returned = 0;
6106 FILE_UNIX_BASIC_INFO *data_offset;
6107 __u16 params, param_offset, offset, count, byte_count;
6108
Joe Perchesf96637b2013-05-04 22:12:25 -05006109 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110setPermsRetry:
6111 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6112 (void **) &pSMBr);
6113 if (rc)
6114 return rc;
6115
6116 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6117 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006118 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006119 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 name_len++; /* trailing null */
6121 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006122 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006123 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006125 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126 }
6127
6128 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006129 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006131 /* BB find max SMB PDU from sess structure BB */
6132 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133 pSMB->MaxSetupCount = 0;
6134 pSMB->Reserved = 0;
6135 pSMB->Flags = 0;
6136 pSMB->Timeout = 0;
6137 pSMB->Reserved2 = 0;
6138 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006139 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140 offset = param_offset + params;
6141 data_offset =
6142 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6143 offset);
6144 memset(data_offset, 0, count);
6145 pSMB->DataOffset = cpu_to_le16(offset);
6146 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6147 pSMB->SetupCount = 1;
6148 pSMB->Reserved3 = 0;
6149 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6150 byte_count = 3 /* pad */ + params + count;
6151 pSMB->ParameterCount = cpu_to_le16(params);
6152 pSMB->DataCount = cpu_to_le16(count);
6153 pSMB->TotalParameterCount = pSMB->ParameterCount;
6154 pSMB->TotalDataCount = pSMB->DataCount;
6155 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6156 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006157 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006158
Jeff Layton654cf142009-07-09 20:02:49 -04006159 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160
6161 pSMB->ByteCount = cpu_to_le16(byte_count);
6162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006164 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006165 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Steve French0d817bc2008-05-22 02:02:03 +00006167 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168 if (rc == -EAGAIN)
6169 goto setPermsRetry;
6170 return rc;
6171}
6172
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006174/*
6175 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6176 * function used by listxattr and getxattr type calls. When ea_name is set,
6177 * it looks for that attribute name and stuffs that value into the EAData
6178 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6179 * buffer. In both cases, the return value is either the length of the
6180 * resulting data or a negative error code. If EAData is a NULL pointer then
6181 * the data isn't copied to it, but the length is returned.
6182 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006184CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006185 const unsigned char *searchName, const unsigned char *ea_name,
6186 char *EAData, size_t buf_size,
6187 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188{
6189 /* BB assumes one setup word */
6190 TRANSACTION2_QPI_REQ *pSMB = NULL;
6191 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6192 int rc = 0;
6193 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006194 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006195 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006196 struct fea *temp_fea;
6197 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006198 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006199 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006200 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201
Joe Perchesf96637b2013-05-04 22:12:25 -05006202 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203QAllEAsRetry:
6204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6205 (void **) &pSMBr);
6206 if (rc)
6207 return rc;
6208
6209 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006210 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006211 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6212 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006213 list_len++; /* trailing null */
6214 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006216 list_len = strnlen(searchName, PATH_MAX);
6217 list_len++; /* trailing null */
6218 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 }
6220
Jeff Layton6e462b92010-02-10 16:18:26 -05006221 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 pSMB->TotalDataCount = 0;
6223 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006224 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006225 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226 pSMB->MaxSetupCount = 0;
6227 pSMB->Reserved = 0;
6228 pSMB->Flags = 0;
6229 pSMB->Timeout = 0;
6230 pSMB->Reserved2 = 0;
6231 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006232 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233 pSMB->DataCount = 0;
6234 pSMB->DataOffset = 0;
6235 pSMB->SetupCount = 1;
6236 pSMB->Reserved3 = 0;
6237 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6238 byte_count = params + 1 /* pad */ ;
6239 pSMB->TotalParameterCount = cpu_to_le16(params);
6240 pSMB->ParameterCount = pSMB->TotalParameterCount;
6241 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6242 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006243 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 pSMB->ByteCount = cpu_to_le16(byte_count);
6245
6246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6248 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006249 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006250 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006252
6253
6254 /* BB also check enough total bytes returned */
6255 /* BB we need to improve the validity checking
6256 of these trans2 responses */
6257
6258 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006259 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006260 rc = -EIO; /* bad smb */
6261 goto QAllEAsOut;
6262 }
6263
6264 /* check that length of list is not more than bcc */
6265 /* check that each entry does not go beyond length
6266 of list */
6267 /* check that each element of each entry does not
6268 go beyond end of list */
6269 /* validate_trans2_offsets() */
6270 /* BB check if start of smb + data_offset > &bcc+ bcc */
6271
6272 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6273 ea_response_data = (struct fealist *)
6274 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6275
Jeff Layton6e462b92010-02-10 16:18:26 -05006276 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006277 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006278 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006279 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006280 /* didn't find the named attribute */
6281 if (ea_name)
6282 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006283 goto QAllEAsOut;
6284 }
6285
Jeff Layton0cd126b2010-02-10 16:18:26 -05006286 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006287 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006288 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006289 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006290 rc = -EIO;
6291 goto QAllEAsOut;
6292 }
6293
Jeff Laytonf0d38682010-02-10 16:18:26 -05006294 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006295 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006296 temp_fea = ea_response_data->list;
6297 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006298 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006299 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006300 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006301
Jeff Layton6e462b92010-02-10 16:18:26 -05006302 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006303 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006304 /* make sure we can read name_len and value_len */
6305 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006306 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006307 rc = -EIO;
6308 goto QAllEAsOut;
6309 }
6310
6311 name_len = temp_fea->name_len;
6312 value_len = le16_to_cpu(temp_fea->value_len);
6313 list_len -= name_len + 1 + value_len;
6314 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006315 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006316 rc = -EIO;
6317 goto QAllEAsOut;
6318 }
6319
Jeff Layton31c05192010-02-10 16:18:26 -05006320 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006321 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006322 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006323 temp_ptr += name_len + 1;
6324 rc = value_len;
6325 if (buf_size == 0)
6326 goto QAllEAsOut;
6327 if ((size_t)value_len > buf_size) {
6328 rc = -ERANGE;
6329 goto QAllEAsOut;
6330 }
6331 memcpy(EAData, temp_ptr, value_len);
6332 goto QAllEAsOut;
6333 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006334 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006335 /* account for prefix user. and trailing null */
6336 rc += (5 + 1 + name_len);
6337 if (rc < (int) buf_size) {
6338 memcpy(EAData, "user.", 5);
6339 EAData += 5;
6340 memcpy(EAData, temp_ptr, name_len);
6341 EAData += name_len;
6342 /* null terminate name */
6343 *EAData = 0;
6344 ++EAData;
6345 } else if (buf_size == 0) {
6346 /* skip copy - calc size only */
6347 } else {
6348 /* stop before overrun buffer */
6349 rc = -ERANGE;
6350 break;
6351 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006352 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006353 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006354 temp_fea = (struct fea *)temp_ptr;
6355 }
6356
Jeff Layton31c05192010-02-10 16:18:26 -05006357 /* didn't find the named attribute */
6358 if (ea_name)
6359 rc = -ENODATA;
6360
Jeff Laytonf0d38682010-02-10 16:18:26 -05006361QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006362 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 if (rc == -EAGAIN)
6364 goto QAllEAsRetry;
6365
6366 return (ssize_t)rc;
6367}
6368
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006370CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6371 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006372 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6373 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374{
6375 struct smb_com_transaction2_spi_req *pSMB = NULL;
6376 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6377 struct fealist *parm_data;
6378 int name_len;
6379 int rc = 0;
6380 int bytes_returned = 0;
6381 __u16 params, param_offset, byte_count, offset, count;
6382
Joe Perchesf96637b2013-05-04 22:12:25 -05006383 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384SetEARetry:
6385 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6386 (void **) &pSMBr);
6387 if (rc)
6388 return rc;
6389
6390 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6391 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006392 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6393 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394 name_len++; /* trailing null */
6395 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006396 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 name_len = strnlen(fileName, PATH_MAX);
6398 name_len++; /* trailing null */
6399 strncpy(pSMB->FileName, fileName, name_len);
6400 }
6401
6402 params = 6 + name_len;
6403
6404 /* done calculating parms using name_len of file name,
6405 now use name_len to calculate length of ea name
6406 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006407 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 name_len = 0;
6409 else
Steve French50c2f752007-07-13 00:33:32 +00006410 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006412 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006414 /* BB find max SMB PDU from sess */
6415 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416 pSMB->MaxSetupCount = 0;
6417 pSMB->Reserved = 0;
6418 pSMB->Flags = 0;
6419 pSMB->Timeout = 0;
6420 pSMB->Reserved2 = 0;
6421 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006422 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006423 offset = param_offset + params;
6424 pSMB->InformationLevel =
6425 cpu_to_le16(SMB_SET_FILE_EA);
6426
Arnd Bergmann4bf53b52018-02-02 16:48:47 +01006427 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6429 pSMB->DataOffset = cpu_to_le16(offset);
6430 pSMB->SetupCount = 1;
6431 pSMB->Reserved3 = 0;
6432 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6433 byte_count = 3 /* pad */ + params + count;
6434 pSMB->DataCount = cpu_to_le16(count);
6435 parm_data->list_len = cpu_to_le32(count);
6436 parm_data->list[0].EA_flags = 0;
6437 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006438 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006440 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006441 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442 parm_data->list[0].name[name_len] = 0;
6443 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6444 /* caller ensures that ea_value_len is less than 64K but
6445 we need to ensure that it fits within the smb */
6446
Steve French50c2f752007-07-13 00:33:32 +00006447 /*BB add length check to see if it would fit in
6448 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006449 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6450 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006451 memcpy(parm_data->list[0].name+name_len+1,
6452 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453
6454 pSMB->TotalDataCount = pSMB->DataCount;
6455 pSMB->ParameterCount = cpu_to_le16(params);
6456 pSMB->TotalParameterCount = pSMB->ParameterCount;
6457 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006458 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459 pSMB->ByteCount = cpu_to_le16(byte_count);
6460 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6461 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006462 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006463 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006464
6465 cifs_buf_release(pSMB);
6466
6467 if (rc == -EAGAIN)
6468 goto SetEARetry;
6469
6470 return rc;
6471}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472#endif
Steve French0eff0e22011-02-24 05:39:23 +00006473
6474#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6475/*
6476 * Years ago the kernel added a "dnotify" function for Samba server,
6477 * to allow network clients (such as Windows) to display updated
6478 * lists of files in directory listings automatically when
6479 * files are added by one user when another user has the
6480 * same directory open on their desktop. The Linux cifs kernel
6481 * client hooked into the kernel side of this interface for
6482 * the same reason, but ironically when the VFS moved from
6483 * "dnotify" to "inotify" it became harder to plug in Linux
6484 * network file system clients (the most obvious use case
6485 * for notify interfaces is when multiple users can update
6486 * the contents of the same directory - exactly what network
6487 * file systems can do) although the server (Samba) could
6488 * still use it. For the short term we leave the worker
6489 * function ifdeffed out (below) until inotify is fixed
6490 * in the VFS to make it easier to plug in network file
6491 * system clients. If inotify turns out to be permanently
6492 * incompatible for network fs clients, we could instead simply
6493 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6494 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006495int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006496 const int notify_subdirs, const __u16 netfid,
6497 __u32 filter, struct file *pfile, int multishot,
6498 const struct nls_table *nls_codepage)
6499{
6500 int rc = 0;
6501 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6502 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6503 struct dir_notify_req *dnotify_req;
6504 int bytes_returned;
6505
Joe Perchesf96637b2013-05-04 22:12:25 -05006506 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006507 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6508 (void **) &pSMBr);
6509 if (rc)
6510 return rc;
6511
6512 pSMB->TotalParameterCount = 0 ;
6513 pSMB->TotalDataCount = 0;
6514 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006515 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006516 pSMB->MaxSetupCount = 4;
6517 pSMB->Reserved = 0;
6518 pSMB->ParameterOffset = 0;
6519 pSMB->DataCount = 0;
6520 pSMB->DataOffset = 0;
6521 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6522 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6523 pSMB->ParameterCount = pSMB->TotalParameterCount;
6524 if (notify_subdirs)
6525 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6526 pSMB->Reserved2 = 0;
6527 pSMB->CompletionFilter = cpu_to_le32(filter);
6528 pSMB->Fid = netfid; /* file handle always le */
6529 pSMB->ByteCount = 0;
6530
6531 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6532 (struct smb_hdr *)pSMBr, &bytes_returned,
6533 CIFS_ASYNC_OP);
6534 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006535 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006536 } else {
6537 /* Add file to outstanding requests */
6538 /* BB change to kmem cache alloc */
6539 dnotify_req = kmalloc(
6540 sizeof(struct dir_notify_req),
6541 GFP_KERNEL);
6542 if (dnotify_req) {
6543 dnotify_req->Pid = pSMB->hdr.Pid;
6544 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6545 dnotify_req->Mid = pSMB->hdr.Mid;
6546 dnotify_req->Tid = pSMB->hdr.Tid;
6547 dnotify_req->Uid = pSMB->hdr.Uid;
6548 dnotify_req->netfid = netfid;
6549 dnotify_req->pfile = pfile;
6550 dnotify_req->filter = filter;
6551 dnotify_req->multishot = multishot;
6552 spin_lock(&GlobalMid_Lock);
6553 list_add_tail(&dnotify_req->lhead,
6554 &GlobalDnotifyReqList);
6555 spin_unlock(&GlobalMid_Lock);
6556 } else
6557 rc = -ENOMEM;
6558 }
6559 cifs_buf_release(pSMB);
6560 return rc;
6561}
6562#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */