blob: 8407b07428a69833e0cfad1fe02a28542a0e2ef5 [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;
Steve French50c2f752007-07-13 00:33:32 +0000580 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000581 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
582 count += strlen(protocols[i].name) + 1;
583 /* null at end of source and target buffers anyway */
584 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000585 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 pSMB->ByteCount = cpu_to_le16(count);
587
588 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000590 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000591 goto neg_err_exit;
592
Jeff Layton9bf67e52010-04-24 07:57:46 -0400593 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500594 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000595 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400596 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000597 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000598 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000599 could not negotiate a common dialect */
600 rc = -EOPNOTSUPP;
601 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000602 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400603 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500604 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400605 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000606 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000607 /* unknown wct */
608 rc = -EOPNOTSUPP;
609 goto neg_err_exit;
610 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400611 /* else wct == 17, NTLM or better */
612
Steve French96daf2b2011-05-27 04:34:02 +0000613 server->sec_mode = pSMBr->SecurityMode;
614 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500615 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000616
Steve French254e55e2006-06-04 05:53:15 +0000617 /* one byte, so no need to convert this or EncryptionKeyLen from
618 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300619 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
620 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400621 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000622 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400623 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000624 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500625 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000626 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000627 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
628 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400629
Jeff Laytone598d1d82013-05-26 07:00:59 -0400630 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
631 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500632 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000633 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100634 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
635 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400636 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500637 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400638 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000639 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400640 } else {
641 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000642 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400643 }
Steve French254e55e2006-06-04 05:53:15 +0000644
645signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400646 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400647 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000648neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700649 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000650
Joe Perchesf96637b2013-05-04 22:12:25 -0500651 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 return rc;
653}
654
655int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400656CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
658 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Joe Perchesf96637b2013-05-04 22:12:25 -0500661 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500662
663 /* BB: do we need to check this? These should never be NULL. */
664 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
665 return -EIO;
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500668 * No need to return error on this operation if tid invalidated and
669 * closed on server already e.g. due to tcp session crashing. Also,
670 * the tcon is no longer on the list, so no need to take lock before
671 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 */
Steve French268875b2009-06-25 00:29:21 +0000673 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000674 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Steve French50c2f752007-07-13 00:33:32 +0000676 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700677 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500678 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 return rc;
Steve French133672e2007-11-13 22:41:37 +0000680
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400681 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500683 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Steve French50c2f752007-07-13 00:33:32 +0000685 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500686 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (rc == -EAGAIN)
688 rc = 0;
689
690 return rc;
691}
692
Jeff Layton766fdbb2011-01-11 07:24:21 -0500693/*
694 * This is a no-op for now. We're not really interested in the reply, but
695 * rather in the fact that the server sent one and that server->lstrp
696 * gets updated.
697 *
698 * FIXME: maybe we should consider checking that the reply matches request?
699 */
700static void
701cifs_echo_callback(struct mid_q_entry *mid)
702{
703 struct TCP_Server_Info *server = mid->callback_data;
704
Christopher Oo5fb4e282015-06-25 16:10:48 -0700705 mutex_lock(&server->srv_mutex);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -0700707 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400708 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500709}
710
711int
712CIFSSMBEcho(struct TCP_Server_Info *server)
713{
714 ECHO_REQ *smb;
715 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400716 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700717 struct smb_rqst rqst = { .rq_iov = &iov,
718 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500719
Joe Perchesf96637b2013-05-04 22:12:25 -0500720 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500721
722 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
723 if (rc)
724 return rc;
725
Steve French2ac2ad92017-05-02 13:35:20 -0500726 if (server->capabilities & CAP_UNICODE)
727 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
728
Jeff Layton766fdbb2011-01-11 07:24:21 -0500729 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000730 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500731 smb->hdr.WordCount = 1;
732 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400733 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500734 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000735 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400736 iov.iov_base = smb;
737 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500738
Jeff Laytonfec344e2012-09-18 16:20:35 -0700739 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400740 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500742 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500743
744 cifs_small_buf_release(smb);
745
746 return rc;
747}
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400750CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 LOGOFF_ANDX_REQ *pSMB;
753 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Joe Perchesf96637b2013-05-04 22:12:25 -0500755 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500756
757 /*
758 * BB: do we need to check validity of ses and server? They should
759 * always be valid since we have an active reference. If not, that
760 * should probably be a BUG()
761 */
762 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return -EIO;
764
Steve Frenchd7b619c2010-02-25 05:36:46 +0000765 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000766 if (ses->need_reconnect)
767 goto session_already_dead; /* no need to send SMBlogoff if uid
768 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
770 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000771 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return rc;
773 }
774
Pavel Shilovsky88257362012-05-23 14:01:59 +0400775 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700776
Jeff Layton38d77c52013-05-26 07:01:00 -0400777 if (ses->server->sign)
778 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 pSMB->hdr.Uid = ses->Suid;
781
782 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400783 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000784session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000785 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000788 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 error */
790 if (rc == -EAGAIN)
791 rc = 0;
792 return rc;
793}
794
795int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400796CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
797 const char *fileName, __u16 type,
798 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000799{
800 TRANSACTION2_SPI_REQ *pSMB = NULL;
801 TRANSACTION2_SPI_RSP *pSMBr = NULL;
802 struct unlink_psx_rq *pRqD;
803 int name_len;
804 int rc = 0;
805 int bytes_returned = 0;
806 __u16 params, param_offset, offset, byte_count;
807
Joe Perchesf96637b2013-05-04 22:12:25 -0500808 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000809PsxDelete:
810 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
811 (void **) &pSMBr);
812 if (rc)
813 return rc;
814
815 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
816 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600817 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
818 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000819 name_len++; /* trailing null */
820 name_len *= 2;
821 } else { /* BB add path length overrun check */
822 name_len = strnlen(fileName, PATH_MAX);
823 name_len++; /* trailing null */
824 strncpy(pSMB->FileName, fileName, name_len);
825 }
826
827 params = 6 + name_len;
828 pSMB->MaxParameterCount = cpu_to_le16(2);
829 pSMB->MaxDataCount = 0; /* BB double check this with jra */
830 pSMB->MaxSetupCount = 0;
831 pSMB->Reserved = 0;
832 pSMB->Flags = 0;
833 pSMB->Timeout = 0;
834 pSMB->Reserved2 = 0;
835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
836 InformationLevel) - 4;
837 offset = param_offset + params;
838
839 /* Setup pointer to Request Data (inode type) */
840 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
841 pRqD->type = cpu_to_le16(type);
842 pSMB->ParameterOffset = cpu_to_le16(param_offset);
843 pSMB->DataOffset = cpu_to_le16(offset);
844 pSMB->SetupCount = 1;
845 pSMB->Reserved3 = 0;
846 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
847 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
848
849 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
850 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
851 pSMB->ParameterCount = cpu_to_le16(params);
852 pSMB->TotalParameterCount = pSMB->ParameterCount;
853 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
854 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000855 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000856 pSMB->ByteCount = cpu_to_le16(byte_count);
857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000859 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500860 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000861 cifs_buf_release(pSMB);
862
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400863 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000864
865 if (rc == -EAGAIN)
866 goto PsxDelete;
867
868 return rc;
869}
870
871int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700872CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
873 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
875 DELETE_FILE_REQ *pSMB = NULL;
876 DELETE_FILE_RSP *pSMBr = NULL;
877 int rc = 0;
878 int bytes_returned;
879 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500880 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882DelFileRetry:
883 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
884 (void **) &pSMBr);
885 if (rc)
886 return rc;
887
888 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700889 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
890 PATH_MAX, cifs_sb->local_nls,
891 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 name_len++; /* trailing null */
893 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700894 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700895 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700897 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899 pSMB->SearchAttributes =
900 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
901 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000902 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 pSMB->ByteCount = cpu_to_le16(name_len + 1);
904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400906 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000907 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500908 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 cifs_buf_release(pSMB);
911 if (rc == -EAGAIN)
912 goto DelFileRetry;
913
914 return rc;
915}
916
917int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400918CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
919 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920{
921 DELETE_DIRECTORY_REQ *pSMB = NULL;
922 DELETE_DIRECTORY_RSP *pSMBr = NULL;
923 int rc = 0;
924 int bytes_returned;
925 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500926 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Joe Perchesf96637b2013-05-04 22:12:25 -0500928 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929RmDirRetry:
930 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
931 (void **) &pSMBr);
932 if (rc)
933 return rc;
934
935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400936 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
937 PATH_MAX, cifs_sb->local_nls,
938 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 name_len++; /* trailing null */
940 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700941 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400942 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400944 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946
947 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000948 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 pSMB->ByteCount = cpu_to_le16(name_len + 1);
950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400952 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000953 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500954 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 cifs_buf_release(pSMB);
957 if (rc == -EAGAIN)
958 goto RmDirRetry;
959 return rc;
960}
961
962int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300963CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
964 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
966 int rc = 0;
967 CREATE_DIRECTORY_REQ *pSMB = NULL;
968 CREATE_DIRECTORY_RSP *pSMBr = NULL;
969 int bytes_returned;
970 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500971 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Joe Perchesf96637b2013-05-04 22:12:25 -0500973 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974MkDirRetry:
975 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
976 (void **) &pSMBr);
977 if (rc)
978 return rc;
979
980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600981 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300982 PATH_MAX, cifs_sb->local_nls,
983 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 name_len++; /* trailing null */
985 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700986 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 name_len = strnlen(name, PATH_MAX);
988 name_len++; /* trailing null */
989 strncpy(pSMB->DirName, name, name_len);
990 }
991
992 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000993 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 pSMB->ByteCount = cpu_to_le16(name_len + 1);
995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400997 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000998 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500999 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 cifs_buf_release(pSMB);
1002 if (rc == -EAGAIN)
1003 goto MkDirRetry;
1004 return rc;
1005}
1006
Steve French2dd29d32007-04-23 22:07:35 +00001007int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001008CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1009 __u32 posix_flags, __u64 mode, __u16 *netfid,
1010 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1011 const char *name, const struct nls_table *nls_codepage,
1012 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001013{
1014 TRANSACTION2_SPI_REQ *pSMB = NULL;
1015 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1016 int name_len;
1017 int rc = 0;
1018 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001019 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001020 OPEN_PSX_REQ *pdata;
1021 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001022
Joe Perchesf96637b2013-05-04 22:12:25 -05001023 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001024PsxCreat:
1025 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1026 (void **) &pSMBr);
1027 if (rc)
1028 return rc;
1029
1030 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1031 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001032 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1033 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001034 name_len++; /* trailing null */
1035 name_len *= 2;
1036 } else { /* BB improve the check for buffer overruns BB */
1037 name_len = strnlen(name, PATH_MAX);
1038 name_len++; /* trailing null */
1039 strncpy(pSMB->FileName, name, name_len);
1040 }
1041
1042 params = 6 + name_len;
1043 count = sizeof(OPEN_PSX_REQ);
1044 pSMB->MaxParameterCount = cpu_to_le16(2);
1045 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1046 pSMB->MaxSetupCount = 0;
1047 pSMB->Reserved = 0;
1048 pSMB->Flags = 0;
1049 pSMB->Timeout = 0;
1050 pSMB->Reserved2 = 0;
1051 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001052 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001053 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001054 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001055 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001056 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001057 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001058 pdata->OpenFlags = cpu_to_le32(*pOplock);
1059 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1060 pSMB->DataOffset = cpu_to_le16(offset);
1061 pSMB->SetupCount = 1;
1062 pSMB->Reserved3 = 0;
1063 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1064 byte_count = 3 /* pad */ + params + count;
1065
1066 pSMB->DataCount = cpu_to_le16(count);
1067 pSMB->ParameterCount = cpu_to_le16(params);
1068 pSMB->TotalDataCount = pSMB->DataCount;
1069 pSMB->TotalParameterCount = pSMB->ParameterCount;
1070 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1071 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001072 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001073 pSMB->ByteCount = cpu_to_le16(byte_count);
1074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1076 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001077 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001078 goto psx_create_err;
1079 }
1080
Joe Perchesf96637b2013-05-04 22:12:25 -05001081 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001082 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1083
Jeff Layton820a8032011-05-04 08:05:26 -04001084 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001085 rc = -EIO; /* bad smb */
1086 goto psx_create_err;
1087 }
1088
1089 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001090 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001091 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001092
Steve French2dd29d32007-04-23 22:07:35 +00001093 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001094 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001095 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1096 /* Let caller know file was created so we can set the mode. */
1097 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001098 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001099 *pOplock |= CIFS_CREATE_ACTION;
1100 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001101 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1102 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001103 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001104 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001105 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001106 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001107 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001108 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001109 goto psx_create_err;
1110 }
Steve French50c2f752007-07-13 00:33:32 +00001111 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001112 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001113 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001114 }
Steve French2dd29d32007-04-23 22:07:35 +00001115
1116psx_create_err:
1117 cifs_buf_release(pSMB);
1118
Steve French65bc98b2009-07-10 15:27:25 +00001119 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001120 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001121 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001122 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001123
1124 if (rc == -EAGAIN)
1125 goto PsxCreat;
1126
Steve French50c2f752007-07-13 00:33:32 +00001127 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001128}
1129
Steve Frencha9d02ad2005-08-24 23:06:05 -07001130static __u16 convert_disposition(int disposition)
1131{
1132 __u16 ofun = 0;
1133
1134 switch (disposition) {
1135 case FILE_SUPERSEDE:
1136 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1137 break;
1138 case FILE_OPEN:
1139 ofun = SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_CREATE:
1142 ofun = SMBOPEN_OCREATE;
1143 break;
1144 case FILE_OPEN_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1146 break;
1147 case FILE_OVERWRITE:
1148 ofun = SMBOPEN_OTRUNC;
1149 break;
1150 case FILE_OVERWRITE_IF:
1151 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1152 break;
1153 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001154 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001155 ofun = SMBOPEN_OAPPEND; /* regular open */
1156 }
1157 return ofun;
1158}
1159
Jeff Layton35fc37d2008-05-14 10:22:03 -07001160static int
1161access_flags_to_smbopen_mode(const int access_flags)
1162{
1163 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1164
1165 if (masked_flags == GENERIC_READ)
1166 return SMBOPEN_READ;
1167 else if (masked_flags == GENERIC_WRITE)
1168 return SMBOPEN_WRITE;
1169
1170 /* just go for read/write */
1171 return SMBOPEN_READWRITE;
1172}
1173
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001175SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001176 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001177 const int access_flags, const int create_options, __u16 *netfid,
1178 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001179 const struct nls_table *nls_codepage, int remap)
1180{
1181 int rc = -EACCES;
1182 OPENX_REQ *pSMB = NULL;
1183 OPENX_RSP *pSMBr = NULL;
1184 int bytes_returned;
1185 int name_len;
1186 __u16 count;
1187
1188OldOpenRetry:
1189 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1190 (void **) &pSMBr);
1191 if (rc)
1192 return rc;
1193
1194 pSMB->AndXCommand = 0xFF; /* none */
1195
1196 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1197 count = 1; /* account for one byte pad to word boundary */
1198 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001199 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1200 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001201 name_len++; /* trailing null */
1202 name_len *= 2;
1203 } else { /* BB improve check for buffer overruns BB */
1204 count = 0; /* no pad */
1205 name_len = strnlen(fileName, PATH_MAX);
1206 name_len++; /* trailing null */
1207 strncpy(pSMB->fileName, fileName, name_len);
1208 }
1209 if (*pOplock & REQ_OPLOCK)
1210 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001211 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001213
Steve Frencha9d02ad2005-08-24 23:06:05 -07001214 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001215 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1217 /* set file as system file if special file such
1218 as fifo and server expecting SFU style and
1219 no Unix extensions */
1220
Steve French790fe572007-07-07 19:25:05 +00001221 if (create_options & CREATE_OPTION_SPECIAL)
1222 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001223 else /* BB FIXME BB */
1224 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225
Jeff Layton67750fb2008-05-09 22:28:02 +00001226 if (create_options & CREATE_OPTION_READONLY)
1227 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228
1229 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001230/* pSMB->CreateOptions = cpu_to_le32(create_options &
1231 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001233
1234 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001235 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001237 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238
1239 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001241 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001242 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001244 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 } else {
1246 /* BB verify if wct == 15 */
1247
Steve French582d21e2008-05-13 04:54:12 +00001248/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249
1250 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1251 /* Let caller know file was created so we can set the mode. */
1252 /* Do we care about the CreateAction in any other cases? */
1253 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001254/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 *pOplock |= CIFS_CREATE_ACTION; */
1256 /* BB FIXME END */
1257
Steve French790fe572007-07-07 19:25:05 +00001258 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1260 pfile_info->LastAccessTime = 0; /* BB fixme */
1261 pfile_info->LastWriteTime = 0; /* BB fixme */
1262 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001263 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001264 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001266 pfile_info->AllocationSize =
1267 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1268 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001270 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 }
1272 }
1273
1274 cifs_buf_release(pSMB);
1275 if (rc == -EAGAIN)
1276 goto OldOpenRetry;
1277 return rc;
1278}
1279
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001281CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1282 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283{
1284 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001285 OPEN_REQ *req = NULL;
1286 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 int bytes_returned;
1288 int name_len;
1289 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001290 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1291 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001292 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001293 const struct nls_table *nls = cifs_sb->local_nls;
1294 int create_options = oparms->create_options;
1295 int desired_access = oparms->desired_access;
1296 int disposition = oparms->disposition;
1297 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001300 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1301 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (rc)
1303 return rc;
1304
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001305 /* no commands go after this */
1306 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001308 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1309 /* account for one byte pad to word boundary */
1310 count = 1;
1311 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1312 path, PATH_MAX, nls, remap);
1313 /* trailing null */
1314 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001316 req->NameLength = cpu_to_le16(name_len);
1317 } else {
1318 /* BB improve check for buffer overruns BB */
1319 /* no pad */
1320 count = 0;
1321 name_len = strnlen(path, PATH_MAX);
1322 /* trailing null */
1323 name_len++;
1324 req->NameLength = cpu_to_le16(name_len);
1325 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001327
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001328 if (*oplock & REQ_OPLOCK)
1329 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1330 else if (*oplock & REQ_BATCHOPLOCK)
1331 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1332
1333 req->DesiredAccess = cpu_to_le32(desired_access);
1334 req->AllocationSize = 0;
1335
1336 /*
1337 * Set file as system file if special file such as fifo and server
1338 * expecting SFU style and no Unix extensions.
1339 */
1340 if (create_options & CREATE_OPTION_SPECIAL)
1341 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1342 else
1343 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1344
1345 /*
1346 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1347 * sensitive checks for other servers such as Samba.
1348 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001350 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Jeff Layton67750fb2008-05-09 22:28:02 +00001352 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001353 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001354
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001355 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1356 req->CreateDisposition = cpu_to_le32(disposition);
1357 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1358
Steve French09d1db52005-04-28 22:41:08 -07001359 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001360 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1361 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001364 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001366 req->ByteCount = cpu_to_le16(count);
1367 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1368 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001369 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001371 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001372 cifs_buf_release(req);
1373 if (rc == -EAGAIN)
1374 goto openRetry;
1375 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001377
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001378 /* 1 byte no need to le_to_cpu */
1379 *oplock = rsp->OplockLevel;
1380 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001381 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001382
1383 /* Let caller know file was created so we can set the mode. */
1384 /* Do we care about the CreateAction in any other cases? */
1385 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1386 *oplock |= CIFS_CREATE_ACTION;
1387
1388 if (buf) {
1389 /* copy from CreationTime to Attributes */
1390 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1391 /* the file_info buf is endian converted by caller */
1392 buf->AllocationSize = rsp->AllocationSize;
1393 buf->EndOfFile = rsp->EndOfFile;
1394 buf->NumberOfLinks = cpu_to_le32(1);
1395 buf->DeletePending = 0;
1396 }
1397
1398 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 return rc;
1400}
1401
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001402/*
1403 * Discard any remaining data in the current SMB. To do this, we borrow the
1404 * current bigbuf.
1405 */
1406static int
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001407discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001408{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001409 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001410 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001411
1412 while (remaining > 0) {
1413 int length;
1414
1415 length = cifs_read_from_socket(server, server->bigbuf,
1416 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001417 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001418 if (length < 0)
1419 return length;
1420 server->total_read += length;
1421 remaining -= length;
1422 }
1423
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001424 return 0;
1425}
1426
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001427static int
1428cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1429{
1430 int length;
1431 struct cifs_readdata *rdata = mid->callback_data;
1432
1433 length = discard_remaining_data(server);
1434 dequeue_mid(mid, rdata->result);
Sachin Prabhud8fd99d2017-03-03 15:41:38 -08001435 mid->resp_buf = server->smallbuf;
1436 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001437 return length;
1438}
1439
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001440int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001441cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1442{
1443 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001444 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001445 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001446 char *buf = server->smallbuf;
1447 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448
Joe Perchesf96637b2013-05-04 22:12:25 -05001449 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1450 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451
1452 /*
1453 * read the rest of READ_RSP header (sans Data array), or whatever we
1454 * can if there's not enough data. At this point, we've read down to
1455 * the Mid.
1456 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001457 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001458 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001459
Al Viroa6137302016-01-09 19:37:16 -05001460 length = cifs_read_from_socket(server,
1461 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001462 if (length < 0)
1463 return length;
1464 server->total_read += length;
1465
Pavel Shilovsky92d7d3e2017-07-08 14:32:00 -07001466 if (server->ops->is_session_expired &&
1467 server->ops->is_session_expired(buf)) {
1468 cifs_reconnect(server);
1469 wake_up(&server->response_q);
1470 return -1;
1471 }
1472
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001473 if (server->ops->is_status_pending &&
1474 server->ops->is_status_pending(buf, server, 0)) {
1475 discard_remaining_data(server);
1476 return -1;
1477 }
1478
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001480 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001482 cifs_dbg(FYI, "%s: server returned error %d\n",
1483 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001484 return cifs_readv_discard(server, mid);
1485 }
1486
1487 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001488 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001489 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1490 __func__, server->total_read,
1491 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001492 rdata->result = -EIO;
1493 return cifs_readv_discard(server, mid);
1494 }
1495
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001496 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001497 if (data_offset < server->total_read) {
1498 /*
1499 * win2k8 sometimes sends an offset of 0 when the read
1500 * is beyond the EOF. Treat it as if the data starts just after
1501 * the header.
1502 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001503 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1504 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001505 data_offset = server->total_read;
1506 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1507 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001508 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1509 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001510 rdata->result = -EIO;
1511 return cifs_readv_discard(server, mid);
1512 }
1513
Joe Perchesf96637b2013-05-04 22:12:25 -05001514 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1515 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516
1517 len = data_offset - server->total_read;
1518 if (len > 0) {
1519 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001520 length = cifs_read_from_socket(server,
1521 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522 if (length < 0)
1523 return length;
1524 server->total_read += length;
1525 }
1526
1527 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001528 rdata->iov.iov_base = buf;
1529 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001530 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1531 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001532
1533 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001534 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001535 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536 /* data_len is corrupt -- discard frame */
1537 rdata->result = -EIO;
1538 return cifs_readv_discard(server, mid);
1539 }
1540
Jeff Layton8321fec2012-09-19 06:22:32 -07001541 length = rdata->read_into_pages(server, rdata, data_len);
1542 if (length < 0)
1543 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001544
Jeff Layton8321fec2012-09-19 06:22:32 -07001545 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001546
Joe Perchesf96637b2013-05-04 22:12:25 -05001547 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1548 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549
1550 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001551 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001552 return cifs_readv_discard(server, mid);
1553
1554 dequeue_mid(mid, false);
Sachin Prabhud8fd99d2017-03-03 15:41:38 -08001555 mid->resp_buf = server->smallbuf;
1556 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557 return length;
1558}
1559
1560static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001561cifs_readv_callback(struct mid_q_entry *mid)
1562{
1563 struct cifs_readdata *rdata = mid->callback_data;
1564 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1565 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001566 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1567 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001568 .rq_pages = rdata->pages,
1569 .rq_npages = rdata->nr_pages,
1570 .rq_pagesz = rdata->pagesz,
1571 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572
Joe Perchesf96637b2013-05-04 22:12:25 -05001573 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1574 __func__, mid->mid, mid->mid_state, rdata->result,
1575 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001576
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001577 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001578 case MID_RESPONSE_RECEIVED:
1579 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001580 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001581 int rc = 0;
1582
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001583 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001584 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001585 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001586 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1587 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001588 }
1589 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001590 task_io_account_read(rdata->got_bytes);
1591 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001592 break;
1593 case MID_REQUEST_SUBMITTED:
1594 case MID_RETRY_NEEDED:
1595 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001596 if (server->sign && rdata->got_bytes)
1597 /* reset bytes number since we can not check a sign */
1598 rdata->got_bytes = 0;
1599 /* FIXME: should this be counted toward the initiating task? */
1600 task_io_account_read(rdata->got_bytes);
1601 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602 break;
1603 default:
1604 rdata->result = -EIO;
1605 }
1606
Jeff Laytonda472fc2012-03-23 14:40:53 -04001607 queue_work(cifsiod_wq, &rdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001608 mutex_lock(&server->srv_mutex);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001609 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001610 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001611 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001612}
1613
1614/* cifs_async_readv - send an async write, and set up mid to handle result */
1615int
1616cifs_async_readv(struct cifs_readdata *rdata)
1617{
1618 int rc;
1619 READ_REQ *smb = NULL;
1620 int wct;
1621 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001622 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001623 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001624
Joe Perchesf96637b2013-05-04 22:12:25 -05001625 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1626 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001627
1628 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1629 wct = 12;
1630 else {
1631 wct = 10; /* old style read */
1632 if ((rdata->offset >> 32) > 0) {
1633 /* can not handle this big offset for old */
1634 return -EIO;
1635 }
1636 }
1637
1638 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1639 if (rc)
1640 return rc;
1641
1642 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1643 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1644
1645 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001646 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001647 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1648 if (wct == 12)
1649 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1650 smb->Remaining = 0;
1651 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1652 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1653 if (wct == 12)
1654 smb->ByteCount = 0;
1655 else {
1656 /* old style read */
1657 struct smb_com_readx_req *smbr =
1658 (struct smb_com_readx_req *)smb;
1659 smbr->ByteCount = 0;
1660 }
1661
1662 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001663 rdata->iov.iov_base = smb;
1664 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001665
Jeff Layton6993f742012-05-16 07:13:17 -04001666 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001667 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1668 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001669
1670 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001671 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001672 else
1673 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001674
1675 cifs_small_buf_release(smb);
1676 return rc;
1677}
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001680CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1681 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682{
1683 int rc = -EACCES;
1684 READ_REQ *pSMB = NULL;
1685 READ_RSP *pSMBr = NULL;
1686 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001687 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001688 int resp_buf_type = 0;
1689 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001690 __u32 pid = io_parms->pid;
1691 __u16 netfid = io_parms->netfid;
1692 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001693 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001694 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Joe Perchesf96637b2013-05-04 22:12:25 -05001696 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001697 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001698 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001699 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001700 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001701 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001702 /* can not handle this big offset for old */
1703 return -EIO;
1704 }
1705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
1707 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001708 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 if (rc)
1710 return rc;
1711
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001712 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1713 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 /* tcon and ses pointer are checked in smb_init */
1716 if (tcon->ses->server == NULL)
1717 return -ECONNABORTED;
1718
Steve Frenchec637e32005-12-12 20:53:18 -08001719 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001721 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001722 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001723 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001724
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 pSMB->Remaining = 0;
1726 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1727 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001728 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001729 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1730 else {
1731 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001732 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001733 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001734 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001735 }
Steve Frenchec637e32005-12-12 20:53:18 -08001736
1737 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001738 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001739 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001740 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001741 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001742 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001744 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 } else {
1746 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1747 data_length = data_length << 16;
1748 data_length += le16_to_cpu(pSMBr->DataLength);
1749 *nbytes = data_length;
1750
1751 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001752 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001754 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001755 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 rc = -EIO;
1757 *nbytes = 0;
1758 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001759 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001760 le16_to_cpu(pSMBr->DataOffset);
1761/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001762 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001763 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001764 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001765 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001766 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 }
1768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
Steve French4b8f9302006-02-26 16:41:18 +00001770/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001771 if (*buf) {
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01001772 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001773 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001774 /* return buffer to caller to free */
1775 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001776 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001777 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001778 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001779 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001780 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001781
1782 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 since file handle passed in no longer valid */
1784 return rc;
1785}
1786
Steve Frenchec637e32005-12-12 20:53:18 -08001787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001789CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001790 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791{
1792 int rc = -EACCES;
1793 WRITE_REQ *pSMB = NULL;
1794 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001795 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 __u32 bytes_sent;
1797 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001798 __u32 pid = io_parms->pid;
1799 __u16 netfid = io_parms->netfid;
1800 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001801 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001802 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Steve Frencha24e2d72010-04-03 17:20:21 +00001804 *nbytes = 0;
1805
Joe Perchesf96637b2013-05-04 22:12:25 -05001806 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001807 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001808 return -ECONNABORTED;
1809
Steve French790fe572007-07-07 19:25:05 +00001810 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001811 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001812 else {
Steve French1c955182005-08-30 20:58:07 -07001813 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001814 if ((offset >> 32) > 0) {
1815 /* can not handle big offset for old srv */
1816 return -EIO;
1817 }
1818 }
Steve French1c955182005-08-30 20:58:07 -07001819
1820 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 (void **) &pSMBr);
1822 if (rc)
1823 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001824
1825 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1826 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 /* tcon and ses pointer are checked in smb_init */
1829 if (tcon->ses->server == NULL)
1830 return -ECONNABORTED;
1831
1832 pSMB->AndXCommand = 0xFF; /* none */
1833 pSMB->Fid = netfid;
1834 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001835 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001836 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 pSMB->Reserved = 0xFFFFFFFF;
1839 pSMB->WriteMode = 0;
1840 pSMB->Remaining = 0;
1841
Steve French50c2f752007-07-13 00:33:32 +00001842 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 can send more if LARGE_WRITE_X capability returned by the server and if
1844 our buffer is big enough or if we convert to iovecs on socket writes
1845 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001846 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1848 } else {
1849 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1850 & ~0xFF;
1851 }
1852
1853 if (bytes_sent > count)
1854 bytes_sent = count;
1855 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001856 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001857 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001858 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001859 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 /* No buffer */
1861 cifs_buf_release(pSMB);
1862 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001863 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001864 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001865 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001866 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001867 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1870 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001871 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001872
Steve French790fe572007-07-07 19:25:05 +00001873 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001874 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001875 else { /* old style write has byte count 4 bytes earlier
1876 so 4 bytes pad */
1877 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001878 (struct smb_com_writex_req *)pSMB;
1879 pSMBW->ByteCount = cpu_to_le16(byte_count);
1880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001883 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001884 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001886 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 } else {
1888 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1889 *nbytes = (*nbytes) << 16;
1890 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301891
1892 /*
1893 * Mask off high 16 bits when bytes written as returned by the
1894 * server is greater than bytes requested by the client. Some
1895 * OS/2 servers are known to set incorrect CountHigh values.
1896 */
1897 if (*nbytes > count)
1898 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
1900
1901 cifs_buf_release(pSMB);
1902
Steve French50c2f752007-07-13 00:33:32 +00001903 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 since file handle passed in no longer valid */
1905
1906 return rc;
1907}
1908
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001909void
1910cifs_writedata_release(struct kref *refcount)
1911{
1912 struct cifs_writedata *wdata = container_of(refcount,
1913 struct cifs_writedata, refcount);
1914
1915 if (wdata->cfile)
1916 cifsFileInfo_put(wdata->cfile);
1917
1918 kfree(wdata);
1919}
1920
1921/*
1922 * Write failed with a retryable error. Resend the write request. It's also
1923 * possible that the page was redirtied so re-clean the page.
1924 */
1925static void
1926cifs_writev_requeue(struct cifs_writedata *wdata)
1927{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001928 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001929 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001930 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001931 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001932
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001933 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1934 i = 0;
1935 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001936 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001937 struct cifs_writedata *wdata2;
1938 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001939
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001940 wsize = server->ops->wp_retry_size(inode);
1941 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001942 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001943 if (!nr_pages) {
1944 rc = -ENOTSUPP;
1945 break;
1946 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001947 cur_len = nr_pages * PAGE_SIZE;
1948 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001949 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001950 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001951 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001952 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001953 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001954
1955 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1956 if (!wdata2) {
1957 rc = -ENOMEM;
1958 break;
1959 }
1960
1961 for (j = 0; j < nr_pages; j++) {
1962 wdata2->pages[j] = wdata->pages[i + j];
1963 lock_page(wdata2->pages[j]);
1964 clear_page_dirty_for_io(wdata2->pages[j]);
1965 }
1966
1967 wdata2->sync_mode = wdata->sync_mode;
1968 wdata2->nr_pages = nr_pages;
1969 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001970 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001971 wdata2->tailsz = tailsz;
1972 wdata2->bytes = cur_len;
1973
1974 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1975 if (!wdata2->cfile) {
1976 cifs_dbg(VFS, "No writable handles for inode\n");
1977 rc = -EBADF;
1978 break;
1979 }
1980 wdata2->pid = wdata2->cfile->pid;
1981 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1982
1983 for (j = 0; j < nr_pages; j++) {
1984 unlock_page(wdata2->pages[j]);
1985 if (rc != 0 && rc != -EAGAIN) {
1986 SetPageError(wdata2->pages[j]);
1987 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001988 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001989 }
1990 }
1991
1992 if (rc) {
1993 kref_put(&wdata2->refcount, cifs_writedata_release);
1994 if (rc == -EAGAIN)
1995 continue;
1996 break;
1997 }
1998
1999 rest_len -= cur_len;
2000 i += nr_pages;
2001 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002002
2003 mapping_set_error(inode->i_mapping, rc);
2004 kref_put(&wdata->refcount, cifs_writedata_release);
2005}
2006
Jeff Laytonc2e87642012-03-23 14:40:55 -04002007void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002008cifs_writev_complete(struct work_struct *work)
2009{
2010 struct cifs_writedata *wdata = container_of(work,
2011 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002012 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002013 int i = 0;
2014
2015 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002016 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002017 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002018 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002019 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2020 wdata->bytes);
2021 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2022 return cifs_writev_requeue(wdata);
2023
2024 for (i = 0; i < wdata->nr_pages; i++) {
2025 struct page *page = wdata->pages[i];
2026 if (wdata->result == -EAGAIN)
2027 __set_page_dirty_nobuffers(page);
2028 else if (wdata->result < 0)
2029 SetPageError(page);
2030 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002031 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002032 }
2033 if (wdata->result != -EAGAIN)
2034 mapping_set_error(inode->i_mapping, wdata->result);
2035 kref_put(&wdata->refcount, cifs_writedata_release);
2036}
2037
2038struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002039cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040{
2041 struct cifs_writedata *wdata;
2042
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002043 /* writedata + number of page pointers */
2044 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002045 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002046 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002047 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002048 INIT_LIST_HEAD(&wdata->list);
2049 init_completion(&wdata->done);
2050 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002051 }
2052 return wdata;
2053}
2054
2055/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002056 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002057 * workqueue completion task.
2058 */
2059static void
2060cifs_writev_callback(struct mid_q_entry *mid)
2061{
2062 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002063 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002064 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002065 unsigned int written;
2066 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2067
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002068 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002069 case MID_RESPONSE_RECEIVED:
2070 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2071 if (wdata->result != 0)
2072 break;
2073
2074 written = le16_to_cpu(smb->CountHigh);
2075 written <<= 16;
2076 written += le16_to_cpu(smb->Count);
2077 /*
2078 * Mask off high 16 bits when bytes written as returned
2079 * by the server is greater than bytes requested by the
2080 * client. OS/2 servers are known to set incorrect
2081 * CountHigh values.
2082 */
2083 if (written > wdata->bytes)
2084 written &= 0xFFFF;
2085
2086 if (written < wdata->bytes)
2087 wdata->result = -ENOSPC;
2088 else
2089 wdata->bytes = written;
2090 break;
2091 case MID_REQUEST_SUBMITTED:
2092 case MID_RETRY_NEEDED:
2093 wdata->result = -EAGAIN;
2094 break;
2095 default:
2096 wdata->result = -EIO;
2097 break;
2098 }
2099
Jeff Laytonda472fc2012-03-23 14:40:53 -04002100 queue_work(cifsiod_wq, &wdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002101 mutex_lock(&server->srv_mutex);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002103 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002104 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002105}
2106
2107/* cifs_async_writev - send an async write, and set up mid to handle result */
2108int
Steve French4a5c80d2014-02-07 20:45:12 -06002109cifs_async_writev(struct cifs_writedata *wdata,
2110 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002112 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002113 WRITE_REQ *smb = NULL;
2114 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002115 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002116 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002117 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002118
2119 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2120 wct = 14;
2121 } else {
2122 wct = 12;
2123 if (wdata->offset >> 32 > 0) {
2124 /* can not handle big offset for old srv */
2125 return -EIO;
2126 }
2127 }
2128
2129 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2130 if (rc)
2131 goto async_writev_out;
2132
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002133 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2134 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002135
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002136 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002137 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002138 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2139 if (wct == 14)
2140 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2141 smb->Reserved = 0xFFFFFFFF;
2142 smb->WriteMode = 0;
2143 smb->Remaining = 0;
2144
2145 smb->DataOffset =
2146 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2147
2148 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002149 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2150 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002151
Jeff Laytoneddb0792012-09-18 16:20:35 -07002152 rqst.rq_iov = &iov;
2153 rqst.rq_nvec = 1;
2154 rqst.rq_pages = wdata->pages;
2155 rqst.rq_npages = wdata->nr_pages;
2156 rqst.rq_pagesz = wdata->pagesz;
2157 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002158
Joe Perchesf96637b2013-05-04 22:12:25 -05002159 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2160 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002161
2162 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2163 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2164
2165 if (wct == 14) {
2166 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2167 put_bcc(wdata->bytes + 1, &smb->hdr);
2168 } else {
2169 /* wct == 12 */
2170 struct smb_com_writex_req *smbw =
2171 (struct smb_com_writex_req *)smb;
2172 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2173 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002174 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002175 }
2176
2177 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002178 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2179 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002180
2181 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002182 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002183 else
Steve French4a5c80d2014-02-07 20:45:12 -06002184 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002185
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002186async_writev_out:
2187 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002188 return rc;
2189}
2190
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002191int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002192CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002193 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194{
2195 int rc = -EACCES;
2196 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002197 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002198 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002199 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002200 __u32 pid = io_parms->pid;
2201 __u16 netfid = io_parms->netfid;
2202 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002203 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002204 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002206 *nbytes = 0;
2207
Joe Perchesf96637b2013-05-04 22:12:25 -05002208 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002209
Steve French4c3130e2008-12-09 00:28:16 +00002210 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002211 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002212 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002213 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002214 if ((offset >> 32) > 0) {
2215 /* can not handle big offset for old srv */
2216 return -EIO;
2217 }
2218 }
Steve French8cc64c62005-10-03 13:49:43 -07002219 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if (rc)
2221 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002222
2223 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2224 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2225
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 /* tcon and ses pointer are checked in smb_init */
2227 if (tcon->ses->server == NULL)
2228 return -ECONNABORTED;
2229
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002230 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 pSMB->Fid = netfid;
2232 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002233 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002234 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 pSMB->Reserved = 0xFFFFFFFF;
2236 pSMB->WriteMode = 0;
2237 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002238
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002240 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
Steve French3e844692005-10-03 13:37:24 -07002242 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2243 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002244 /* header + 1 byte pad */
2245 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002246 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002247 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002248 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002249 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002250 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002251 pSMB->ByteCount = cpu_to_le16(count + 1);
2252 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002253 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002254 (struct smb_com_writex_req *)pSMB;
2255 pSMBW->ByteCount = cpu_to_le16(count + 5);
2256 }
Steve French3e844692005-10-03 13:37:24 -07002257 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002258 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002259 iov[0].iov_len = smb_hdr_len + 4;
2260 else /* wct == 12 pad bigger by four bytes */
2261 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002262
Steve French3e844692005-10-03 13:37:24 -07002263
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002264 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002265 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002267 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002268 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002269 /* presumably this can not happen, but best to be safe */
2270 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002271 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002272 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002273 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2274 *nbytes = (*nbytes) << 16;
2275 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302276
2277 /*
2278 * Mask off high 16 bits when bytes written as returned by the
2279 * server is greater than bytes requested by the client. OS/2
2280 * servers are known to set incorrect CountHigh values.
2281 */
2282 if (*nbytes > count)
2283 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
Steve French4b8f9302006-02-26 16:41:18 +00002286/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002287 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
Steve French50c2f752007-07-13 00:33:32 +00002289 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 since file handle passed in no longer valid */
2291
2292 return rc;
2293}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002294
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002295int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2296 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002297 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2298{
2299 int rc = 0;
2300 LOCK_REQ *pSMB = NULL;
2301 struct kvec iov[2];
2302 int resp_buf_type;
2303 __u16 count;
2304
Joe Perchesf96637b2013-05-04 22:12:25 -05002305 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2306 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002307
2308 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2309 if (rc)
2310 return rc;
2311
2312 pSMB->Timeout = 0;
2313 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2314 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2315 pSMB->LockType = lock_type;
2316 pSMB->AndXCommand = 0xFF; /* none */
2317 pSMB->Fid = netfid; /* netfid stays le */
2318
2319 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2320 inc_rfc1001_len(pSMB, count);
2321 pSMB->ByteCount = cpu_to_le16(count);
2322
2323 iov[0].iov_base = (char *)pSMB;
2324 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2325 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2326 iov[1].iov_base = (char *)buf;
2327 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2328
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002329 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002330 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2331 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002332 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002333
2334 return rc;
2335}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002336
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002338CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002339 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002341 const __u32 numLock, const __u8 lockType,
2342 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343{
2344 int rc = 0;
2345 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002346/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002348 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 __u16 count;
2350
Joe Perchesf96637b2013-05-04 22:12:25 -05002351 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2352 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002353 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 if (rc)
2356 return rc;
2357
Steve French790fe572007-07-07 19:25:05 +00002358 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002359 /* no response expected */
2360 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002362 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002363 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2365 } else {
2366 pSMB->Timeout = 0;
2367 }
2368
2369 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2370 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2371 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002372 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 pSMB->AndXCommand = 0xFF; /* none */
2374 pSMB->Fid = smb_file_id; /* netfid stays le */
2375
Steve French790fe572007-07-07 19:25:05 +00002376 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002377 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 /* BB where to store pid high? */
2379 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2380 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2381 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2382 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2383 count = sizeof(LOCKING_ANDX_RANGE);
2384 } else {
2385 /* oplock break */
2386 count = 0;
2387 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002388 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 pSMB->ByteCount = cpu_to_le16(count);
2390
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002391 if (waitFlag) {
2392 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002393 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002394 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002395 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002396 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002397 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002398 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002399 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002400 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002401 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
Steve French50c2f752007-07-13 00:33:32 +00002403 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 since file handle passed in no longer valid */
2405 return rc;
2406}
2407
2408int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002409CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002410 const __u16 smb_file_id, const __u32 netpid,
2411 const loff_t start_offset, const __u64 len,
2412 struct file_lock *pLockData, const __u16 lock_type,
2413 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002414{
2415 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2416 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002417 struct cifs_posix_lock *parm_data;
2418 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002419 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002420 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002421 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002422 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002423 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002424
Joe Perchesf96637b2013-05-04 22:12:25 -05002425 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002426
Steve French08547b02006-02-28 22:39:25 +00002427 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2428
2429 if (rc)
2430 return rc;
2431
2432 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2433
Steve French50c2f752007-07-13 00:33:32 +00002434 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002435 pSMB->MaxSetupCount = 0;
2436 pSMB->Reserved = 0;
2437 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002438 pSMB->Reserved2 = 0;
2439 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2440 offset = param_offset + params;
2441
Steve French08547b02006-02-28 22:39:25 +00002442 count = sizeof(struct cifs_posix_lock);
2443 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002444 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002445 pSMB->SetupCount = 1;
2446 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002447 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002448 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2449 else
2450 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2451 byte_count = 3 /* pad */ + params + count;
2452 pSMB->DataCount = cpu_to_le16(count);
2453 pSMB->ParameterCount = cpu_to_le16(params);
2454 pSMB->TotalDataCount = pSMB->DataCount;
2455 pSMB->TotalParameterCount = pSMB->ParameterCount;
2456 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002457 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002458 (((char *) &pSMB->hdr.Protocol) + offset);
2459
2460 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002461 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002462 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002463 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002464 pSMB->Timeout = cpu_to_le32(-1);
2465 } else
2466 pSMB->Timeout = 0;
2467
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002468 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002469 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002470 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002471
2472 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002473 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002474 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2475 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002476 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002477 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002478 if (waitFlag) {
2479 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2480 (struct smb_hdr *) pSMBr, &bytes_returned);
2481 } else {
Steve French133672e2007-11-13 22:41:37 +00002482 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002483 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002484 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2485 &resp_buf_type, timeout);
2486 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2487 not try to free it twice below on exit */
2488 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002489 }
2490
Steve French08547b02006-02-28 22:39:25 +00002491 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002492 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002493 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002494 /* lock structure can be returned on get */
2495 __u16 data_offset;
2496 __u16 data_count;
2497 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002498
Jeff Layton820a8032011-05-04 08:05:26 -04002499 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002500 rc = -EIO; /* bad smb */
2501 goto plk_err_exit;
2502 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002503 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2504 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002505 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002506 rc = -EIO;
2507 goto plk_err_exit;
2508 }
2509 parm_data = (struct cifs_posix_lock *)
2510 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002511 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002512 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002513 else {
2514 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002515 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002516 pLockData->fl_type = F_RDLCK;
2517 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002518 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002519 pLockData->fl_type = F_WRLCK;
2520
Steve French5443d132011-03-13 05:08:25 +00002521 pLockData->fl_start = le64_to_cpu(parm_data->start);
2522 pLockData->fl_end = pLockData->fl_start +
2523 le64_to_cpu(parm_data->length) - 1;
2524 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002525 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002526 }
Steve French50c2f752007-07-13 00:33:32 +00002527
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002528plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002529 if (pSMB)
2530 cifs_small_buf_release(pSMB);
2531
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002532 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French133672e2007-11-13 22:41:37 +00002533
Steve French08547b02006-02-28 22:39:25 +00002534 /* Note: On -EAGAIN error only caller can retry on handle based calls
2535 since file handle passed in no longer valid */
2536
2537 return rc;
2538}
2539
2540
2541int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002542CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543{
2544 int rc = 0;
2545 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002546 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
2548/* do not retry on dead session on close */
2549 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002550 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 return 0;
2552 if (rc)
2553 return rc;
2554
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002556 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002558 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002559 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002561 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002563 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 }
2565 }
2566
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002568 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 rc = 0;
2570
2571 return rc;
2572}
2573
2574int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002575CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002576{
2577 int rc = 0;
2578 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002579 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002580
2581 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2582 if (rc)
2583 return rc;
2584
2585 pSMB->FileID = (__u16) smb_file_id;
2586 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002587 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002588 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002589 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002590 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002591
2592 return rc;
2593}
2594
2595int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002596CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002597 const char *from_name, const char *to_name,
2598 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599{
2600 int rc = 0;
2601 RENAME_REQ *pSMB = NULL;
2602 RENAME_RSP *pSMBr = NULL;
2603 int bytes_returned;
2604 int name_len, name_len2;
2605 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002606 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
Joe Perchesf96637b2013-05-04 22:12:25 -05002608 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609renameRetry:
2610 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2611 (void **) &pSMBr);
2612 if (rc)
2613 return rc;
2614
2615 pSMB->BufferFormat = 0x04;
2616 pSMB->SearchAttributes =
2617 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2618 ATTR_DIRECTORY);
2619
2620 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002621 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2622 from_name, PATH_MAX,
2623 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 name_len++; /* trailing null */
2625 name_len *= 2;
2626 pSMB->OldFileName[name_len] = 0x04; /* pad */
2627 /* protocol requires ASCII signature byte on Unicode string */
2628 pSMB->OldFileName[name_len + 1] = 0x00;
2629 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002630 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002631 to_name, PATH_MAX, cifs_sb->local_nls,
2632 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2634 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002635 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002636 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002638 strncpy(pSMB->OldFileName, from_name, name_len);
2639 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 name_len2++; /* trailing null */
2641 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002642 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 name_len2++; /* trailing null */
2644 name_len2++; /* signature byte */
2645 }
2646
2647 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002648 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 pSMB->ByteCount = cpu_to_le16(count);
2650
2651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002653 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002654 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002655 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 cifs_buf_release(pSMB);
2658
2659 if (rc == -EAGAIN)
2660 goto renameRetry;
2661
2662 return rc;
2663}
2664
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002665int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002666 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002667 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668{
2669 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2670 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002671 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 char *data_offset;
2673 char dummy_string[30];
2674 int rc = 0;
2675 int bytes_returned = 0;
2676 int len_of_str;
2677 __u16 params, param_offset, offset, count, byte_count;
2678
Joe Perchesf96637b2013-05-04 22:12:25 -05002679 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2681 (void **) &pSMBr);
2682 if (rc)
2683 return rc;
2684
2685 params = 6;
2686 pSMB->MaxSetupCount = 0;
2687 pSMB->Reserved = 0;
2688 pSMB->Flags = 0;
2689 pSMB->Timeout = 0;
2690 pSMB->Reserved2 = 0;
2691 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2692 offset = param_offset + params;
2693
2694 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2695 rename_info = (struct set_file_rename *) data_offset;
2696 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002697 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 pSMB->SetupCount = 1;
2699 pSMB->Reserved3 = 0;
2700 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2701 byte_count = 3 /* pad */ + params;
2702 pSMB->ParameterCount = cpu_to_le16(params);
2703 pSMB->TotalParameterCount = pSMB->ParameterCount;
2704 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2705 pSMB->DataOffset = cpu_to_le16(offset);
2706 /* construct random name ".cifs_tmp<inodenum><mid>" */
2707 rename_info->overwrite = cpu_to_le32(1);
2708 rename_info->root_fid = 0;
2709 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002710 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002711 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002712 len_of_str =
2713 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002714 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002716 len_of_str =
2717 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002718 target_name, PATH_MAX, nls_codepage,
2719 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 }
2721 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002722 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 byte_count += count;
2724 pSMB->DataCount = cpu_to_le16(count);
2725 pSMB->TotalDataCount = pSMB->DataCount;
2726 pSMB->Fid = netfid;
2727 pSMB->InformationLevel =
2728 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2729 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002730 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 pSMB->ByteCount = cpu_to_le16(byte_count);
2732 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002733 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002734 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002735 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002736 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2737 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002738
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 cifs_buf_release(pSMB);
2740
2741 /* Note: On -EAGAIN error only caller can retry on handle based calls
2742 since file handle passed in no longer valid */
2743
2744 return rc;
2745}
2746
2747int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002748CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2749 const char *fromName, const __u16 target_tid, const char *toName,
2750 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751{
2752 int rc = 0;
2753 COPY_REQ *pSMB = NULL;
2754 COPY_RSP *pSMBr = NULL;
2755 int bytes_returned;
2756 int name_len, name_len2;
2757 __u16 count;
2758
Joe Perchesf96637b2013-05-04 22:12:25 -05002759 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760copyRetry:
2761 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2762 (void **) &pSMBr);
2763 if (rc)
2764 return rc;
2765
2766 pSMB->BufferFormat = 0x04;
2767 pSMB->Tid2 = target_tid;
2768
2769 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2770
2771 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002772 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2773 fromName, PATH_MAX, nls_codepage,
2774 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 name_len++; /* trailing null */
2776 name_len *= 2;
2777 pSMB->OldFileName[name_len] = 0x04; /* pad */
2778 /* protocol requires ASCII signature byte on Unicode string */
2779 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002780 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002781 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2782 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2784 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002785 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 name_len = strnlen(fromName, PATH_MAX);
2787 name_len++; /* trailing null */
2788 strncpy(pSMB->OldFileName, fromName, name_len);
2789 name_len2 = strnlen(toName, PATH_MAX);
2790 name_len2++; /* trailing null */
2791 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2792 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2793 name_len2++; /* trailing null */
2794 name_len2++; /* signature byte */
2795 }
2796
2797 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002798 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 pSMB->ByteCount = cpu_to_le16(count);
2800
2801 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2802 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2803 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002804 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2805 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 }
Steve French0d817bc2008-05-22 02:02:03 +00002807 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809 if (rc == -EAGAIN)
2810 goto copyRetry;
2811
2812 return rc;
2813}
2814
2815int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002816CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002818 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819{
2820 TRANSACTION2_SPI_REQ *pSMB = NULL;
2821 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2822 char *data_offset;
2823 int name_len;
2824 int name_len_target;
2825 int rc = 0;
2826 int bytes_returned = 0;
2827 __u16 params, param_offset, offset, byte_count;
2828
Joe Perchesf96637b2013-05-04 22:12:25 -05002829 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830createSymLinkRetry:
2831 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2832 (void **) &pSMBr);
2833 if (rc)
2834 return rc;
2835
2836 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2837 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002838 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2839 /* find define for this maxpathcomponent */
2840 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 name_len++; /* trailing null */
2842 name_len *= 2;
2843
Steve French50c2f752007-07-13 00:33:32 +00002844 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 name_len = strnlen(fromName, PATH_MAX);
2846 name_len++; /* trailing null */
2847 strncpy(pSMB->FileName, fromName, name_len);
2848 }
2849 params = 6 + name_len;
2850 pSMB->MaxSetupCount = 0;
2851 pSMB->Reserved = 0;
2852 pSMB->Flags = 0;
2853 pSMB->Timeout = 0;
2854 pSMB->Reserved2 = 0;
2855 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002856 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 offset = param_offset + params;
2858
2859 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2861 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002862 cifsConvertToUTF16((__le16 *) data_offset, toName,
2863 /* find define for this maxpathcomponent */
2864 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 name_len_target++; /* trailing null */
2866 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002867 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 name_len_target = strnlen(toName, PATH_MAX);
2869 name_len_target++; /* trailing null */
2870 strncpy(data_offset, toName, name_len_target);
2871 }
2872
2873 pSMB->MaxParameterCount = cpu_to_le16(2);
2874 /* BB find exact max on data count below from sess */
2875 pSMB->MaxDataCount = cpu_to_le16(1000);
2876 pSMB->SetupCount = 1;
2877 pSMB->Reserved3 = 0;
2878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2879 byte_count = 3 /* pad */ + params + name_len_target;
2880 pSMB->DataCount = cpu_to_le16(name_len_target);
2881 pSMB->ParameterCount = cpu_to_le16(params);
2882 pSMB->TotalDataCount = pSMB->DataCount;
2883 pSMB->TotalParameterCount = pSMB->ParameterCount;
2884 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2885 pSMB->DataOffset = cpu_to_le16(offset);
2886 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2887 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002888 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 pSMB->ByteCount = cpu_to_le16(byte_count);
2890 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2891 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002892 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002893 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002894 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2895 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
Steve French0d817bc2008-05-22 02:02:03 +00002897 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
2899 if (rc == -EAGAIN)
2900 goto createSymLinkRetry;
2901
2902 return rc;
2903}
2904
2905int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002906CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002908 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909{
2910 TRANSACTION2_SPI_REQ *pSMB = NULL;
2911 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2912 char *data_offset;
2913 int name_len;
2914 int name_len_target;
2915 int rc = 0;
2916 int bytes_returned = 0;
2917 __u16 params, param_offset, offset, byte_count;
2918
Joe Perchesf96637b2013-05-04 22:12:25 -05002919 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920createHardLinkRetry:
2921 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2922 (void **) &pSMBr);
2923 if (rc)
2924 return rc;
2925
2926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002927 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2928 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 name_len++; /* trailing null */
2930 name_len *= 2;
2931
Steve French50c2f752007-07-13 00:33:32 +00002932 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 name_len = strnlen(toName, PATH_MAX);
2934 name_len++; /* trailing null */
2935 strncpy(pSMB->FileName, toName, name_len);
2936 }
2937 params = 6 + name_len;
2938 pSMB->MaxSetupCount = 0;
2939 pSMB->Reserved = 0;
2940 pSMB->Flags = 0;
2941 pSMB->Timeout = 0;
2942 pSMB->Reserved2 = 0;
2943 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002944 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 offset = param_offset + params;
2946
2947 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2949 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002950 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2951 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 name_len_target++; /* trailing null */
2953 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002954 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 name_len_target = strnlen(fromName, PATH_MAX);
2956 name_len_target++; /* trailing null */
2957 strncpy(data_offset, fromName, name_len_target);
2958 }
2959
2960 pSMB->MaxParameterCount = cpu_to_le16(2);
2961 /* BB find exact max on data count below from sess*/
2962 pSMB->MaxDataCount = cpu_to_le16(1000);
2963 pSMB->SetupCount = 1;
2964 pSMB->Reserved3 = 0;
2965 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2966 byte_count = 3 /* pad */ + params + name_len_target;
2967 pSMB->ParameterCount = cpu_to_le16(params);
2968 pSMB->TotalParameterCount = pSMB->ParameterCount;
2969 pSMB->DataCount = cpu_to_le16(name_len_target);
2970 pSMB->TotalDataCount = pSMB->DataCount;
2971 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2972 pSMB->DataOffset = cpu_to_le16(offset);
2973 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2974 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002975 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 pSMB->ByteCount = cpu_to_le16(byte_count);
2977 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2978 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002979 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002980 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002981 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2982 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
2984 cifs_buf_release(pSMB);
2985 if (rc == -EAGAIN)
2986 goto createHardLinkRetry;
2987
2988 return rc;
2989}
2990
2991int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002992CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002993 const char *from_name, const char *to_name,
2994 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995{
2996 int rc = 0;
2997 NT_RENAME_REQ *pSMB = NULL;
2998 RENAME_RSP *pSMBr = NULL;
2999 int bytes_returned;
3000 int name_len, name_len2;
3001 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003002 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
Joe Perchesf96637b2013-05-04 22:12:25 -05003004 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005winCreateHardLinkRetry:
3006
3007 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3008 (void **) &pSMBr);
3009 if (rc)
3010 return rc;
3011
3012 pSMB->SearchAttributes =
3013 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3014 ATTR_DIRECTORY);
3015 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3016 pSMB->ClusterCount = 0;
3017
3018 pSMB->BufferFormat = 0x04;
3019
3020 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3021 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003022 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3023 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 name_len++; /* trailing null */
3025 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003026
3027 /* protocol specifies ASCII buffer format (0x04) for unicode */
3028 pSMB->OldFileName[name_len] = 0x04;
3029 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003031 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003032 to_name, PATH_MAX, cifs_sb->local_nls,
3033 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3035 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003036 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003037 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003039 strncpy(pSMB->OldFileName, from_name, name_len);
3040 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 name_len2++; /* trailing null */
3042 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003043 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 name_len2++; /* trailing null */
3045 name_len2++; /* signature byte */
3046 }
3047
3048 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003049 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 pSMB->ByteCount = cpu_to_le16(count);
3051
3052 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3053 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003054 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003055 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003056 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003057
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 cifs_buf_release(pSMB);
3059 if (rc == -EAGAIN)
3060 goto winCreateHardLinkRetry;
3061
3062 return rc;
3063}
3064
3065int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003066CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003067 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003068 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069{
3070/* SMB_QUERY_FILE_UNIX_LINK */
3071 TRANSACTION2_QPI_REQ *pSMB = NULL;
3072 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3073 int rc = 0;
3074 int bytes_returned;
3075 int name_len;
3076 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003077 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078
Joe Perchesf96637b2013-05-04 22:12:25 -05003079 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
3081querySymLinkRetry:
3082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3083 (void **) &pSMBr);
3084 if (rc)
3085 return rc;
3086
3087 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3088 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003089 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3090 searchName, PATH_MAX, nls_codepage,
3091 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 name_len++; /* trailing null */
3093 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003094 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 name_len = strnlen(searchName, PATH_MAX);
3096 name_len++; /* trailing null */
3097 strncpy(pSMB->FileName, searchName, name_len);
3098 }
3099
3100 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3101 pSMB->TotalDataCount = 0;
3102 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003103 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 pSMB->MaxSetupCount = 0;
3105 pSMB->Reserved = 0;
3106 pSMB->Flags = 0;
3107 pSMB->Timeout = 0;
3108 pSMB->Reserved2 = 0;
3109 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003110 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 pSMB->DataCount = 0;
3112 pSMB->DataOffset = 0;
3113 pSMB->SetupCount = 1;
3114 pSMB->Reserved3 = 0;
3115 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3116 byte_count = params + 1 /* pad */ ;
3117 pSMB->TotalParameterCount = cpu_to_le16(params);
3118 pSMB->ParameterCount = pSMB->TotalParameterCount;
3119 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3120 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003121 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 pSMB->ByteCount = cpu_to_le16(byte_count);
3123
3124 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3125 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3126 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003127 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 } else {
3129 /* decode response */
3130
3131 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003133 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003134 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003136 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003137 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
Jeff Layton460b9692009-04-30 07:17:56 -04003139 data_start = ((char *) &pSMBr->hdr.Protocol) +
3140 le16_to_cpu(pSMBr->t2.DataOffset);
3141
Steve French0e0d2cf2009-05-01 05:27:32 +00003142 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3143 is_unicode = true;
3144 else
3145 is_unicode = false;
3146
Steve French737b7582005-04-28 22:41:06 -07003147 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003148 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3149 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003150 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003151 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 }
3153 }
3154 cifs_buf_release(pSMB);
3155 if (rc == -EAGAIN)
3156 goto querySymLinkRetry;
3157 return rc;
3158}
3159
Steve Frenchc52a9552011-02-24 06:16:22 +00003160/*
3161 * Recent Windows versions now create symlinks more frequently
3162 * and they use the "reparse point" mechanism below. We can of course
3163 * do symlinks nicely to Samba and other servers which support the
3164 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3165 * "MF" symlinks optionally, but for recent Windows we really need to
3166 * reenable the code below and fix the cifs_symlink callers to handle this.
3167 * In the interim this code has been moved to its own config option so
3168 * it is not compiled in by default until callers fixed up and more tested.
3169 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003171CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3172 __u16 fid, char **symlinkinfo,
3173 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174{
3175 int rc = 0;
3176 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003177 struct smb_com_transaction_ioctl_req *pSMB;
3178 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003179 bool is_unicode;
3180 unsigned int sub_len;
3181 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003182 struct reparse_symlink_data *reparse_buf;
3183 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003184 __u32 data_offset, data_count;
3185 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003187 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3189 (void **) &pSMBr);
3190 if (rc)
3191 return rc;
3192
3193 pSMB->TotalParameterCount = 0 ;
3194 pSMB->TotalDataCount = 0;
3195 pSMB->MaxParameterCount = cpu_to_le32(2);
3196 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003197 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 pSMB->MaxSetupCount = 4;
3199 pSMB->Reserved = 0;
3200 pSMB->ParameterOffset = 0;
3201 pSMB->DataCount = 0;
3202 pSMB->DataOffset = 0;
3203 pSMB->SetupCount = 4;
3204 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3205 pSMB->ParameterCount = pSMB->TotalParameterCount;
3206 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3207 pSMB->IsFsctl = 1; /* FSCTL */
3208 pSMB->IsRootFlag = 0;
3209 pSMB->Fid = fid; /* file handle always le */
3210 pSMB->ByteCount = 0;
3211
3212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3214 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003215 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003216 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 }
Steve French989c7e52009-05-02 05:32:20 +00003218
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003219 data_offset = le32_to_cpu(pSMBr->DataOffset);
3220 data_count = le32_to_cpu(pSMBr->DataCount);
3221 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3222 /* BB also check enough total bytes returned */
3223 rc = -EIO; /* bad smb */
3224 goto qreparse_out;
3225 }
3226 if (!data_count || (data_count > 2048)) {
3227 rc = -EIO;
3228 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3229 goto qreparse_out;
3230 }
3231 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003232 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003233 ((char *)&pSMBr->hdr.Protocol + data_offset);
3234 if ((char *)reparse_buf >= end_of_smb) {
3235 rc = -EIO;
3236 goto qreparse_out;
3237 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003238 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3239 cifs_dbg(FYI, "NFS style reparse tag\n");
3240 posix_buf = (struct reparse_posix_data *)reparse_buf;
3241
3242 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3243 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3244 le64_to_cpu(posix_buf->InodeType));
3245 rc = -EOPNOTSUPP;
3246 goto qreparse_out;
3247 }
3248 is_unicode = true;
3249 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3250 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3251 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3252 rc = -EIO;
3253 goto qreparse_out;
3254 }
3255 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3256 sub_len, is_unicode, nls_codepage);
3257 goto qreparse_out;
3258 } else if (reparse_buf->ReparseTag !=
3259 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3260 rc = -EOPNOTSUPP;
3261 goto qreparse_out;
3262 }
3263
3264 /* Reparse tag is NTFS symlink */
3265 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3266 reparse_buf->PathBuffer;
3267 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3268 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003269 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3270 rc = -EIO;
3271 goto qreparse_out;
3272 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003273 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3274 is_unicode = true;
3275 else
3276 is_unicode = false;
3277
3278 /* BB FIXME investigate remapping reserved chars here */
3279 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3280 nls_codepage);
3281 if (!*symlinkinfo)
3282 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003284 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003286 /*
3287 * Note: On -EAGAIN error only caller can retry on handle based calls
3288 * since file handle passed in no longer valid.
3289 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 return rc;
3291}
3292
Steve Frenchc7f508a2013-10-14 15:27:32 -05003293int
3294CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3295 __u16 fid)
3296{
3297 int rc = 0;
3298 int bytes_returned;
3299 struct smb_com_transaction_compr_ioctl_req *pSMB;
3300 struct smb_com_transaction_ioctl_rsp *pSMBr;
3301
3302 cifs_dbg(FYI, "Set compression for %u\n", fid);
3303 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3304 (void **) &pSMBr);
3305 if (rc)
3306 return rc;
3307
3308 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3309
3310 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003311 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003312 pSMB->MaxParameterCount = 0;
3313 pSMB->MaxDataCount = 0;
3314 pSMB->MaxSetupCount = 4;
3315 pSMB->Reserved = 0;
3316 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003317 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003318 pSMB->DataOffset =
3319 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3320 compression_state) - 4); /* 84 */
3321 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003322 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003323 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003324 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003325 pSMB->IsFsctl = 1; /* FSCTL */
3326 pSMB->IsRootFlag = 0;
3327 pSMB->Fid = fid; /* file handle always le */
3328 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003329 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003330 inc_rfc1001_len(pSMB, 5);
3331
3332 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3333 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3334 if (rc)
3335 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3336
3337 cifs_buf_release(pSMB);
3338
3339 /*
3340 * Note: On -EAGAIN error only caller can retry on handle based calls
3341 * since file handle passed in no longer valid.
3342 */
3343 return rc;
3344}
3345
3346
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347#ifdef CONFIG_CIFS_POSIX
3348
3349/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003350static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003351 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352{
3353 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003354 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3355 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3356 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003357/*
3358 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3359 ace->e_perm, ace->e_tag, ace->e_id);
3360*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361
3362 return;
3363}
3364
3365/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003366static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3367 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368{
3369 int size = 0;
3370 int i;
3371 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003372 struct cifs_posix_ace *pACE;
3373 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003374 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375
3376 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3377 return -EOPNOTSUPP;
3378
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003379 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 count = le16_to_cpu(cifs_acl->access_entry_count);
3381 pACE = &cifs_acl->ace_array[0];
3382 size = sizeof(struct cifs_posix_acl);
3383 size += sizeof(struct cifs_posix_ace) * count;
3384 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003385 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003386 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3387 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 return -EINVAL;
3389 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003390 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 count = le16_to_cpu(cifs_acl->access_entry_count);
3392 size = sizeof(struct cifs_posix_acl);
3393 size += sizeof(struct cifs_posix_ace) * count;
3394/* skip past access ACEs to get to default ACEs */
3395 pACE = &cifs_acl->ace_array[count];
3396 count = le16_to_cpu(cifs_acl->default_entry_count);
3397 size += sizeof(struct cifs_posix_ace) * count;
3398 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003399 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 return -EINVAL;
3401 } else {
3402 /* illegal type */
3403 return -EINVAL;
3404 }
3405
3406 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003407 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003408 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003409 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 return -ERANGE;
3411 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003412 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3413
Steve Frenchff7feac2005-11-15 16:45:16 -08003414 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003415 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003416 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003417 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 }
3419 }
3420 return size;
3421}
3422
Steve French50c2f752007-07-13 00:33:32 +00003423static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003424 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425{
3426 __u16 rc = 0; /* 0 = ACL converted ok */
3427
Steve Frenchff7feac2005-11-15 16:45:16 -08003428 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3429 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003431 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 /* Probably no need to le convert -1 on any arch but can not hurt */
3433 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003434 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003435 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003436/*
3437 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3438 ace->e_perm, ace->e_tag, ace->e_id);
3439*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 return rc;
3441}
3442
3443/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003444static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3445 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446{
3447 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003448 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003449 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003450 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 int count;
3452 int i;
3453
Steve French790fe572007-07-07 19:25:05 +00003454 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 return 0;
3456
3457 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003458 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3459 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003460 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003461 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3462 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 return 0;
3464 }
3465 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003466 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003467 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003468 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003469 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003470 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003471 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003472 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003473 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 return 0;
3475 }
Steve French50c2f752007-07-13 00:33:32 +00003476 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003477 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003478 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 /* ACE not converted */
3480 break;
3481 }
3482 }
Steve French790fe572007-07-07 19:25:05 +00003483 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3485 rc += sizeof(struct cifs_posix_acl);
3486 /* BB add check to make sure ACL does not overflow SMB */
3487 }
3488 return rc;
3489}
3490
3491int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003492CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003493 const unsigned char *searchName,
3494 char *acl_inf, const int buflen, const int acl_type,
3495 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496{
3497/* SMB_QUERY_POSIX_ACL */
3498 TRANSACTION2_QPI_REQ *pSMB = NULL;
3499 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3500 int rc = 0;
3501 int bytes_returned;
3502 int name_len;
3503 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003504
Joe Perchesf96637b2013-05-04 22:12:25 -05003505 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
3507queryAclRetry:
3508 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3509 (void **) &pSMBr);
3510 if (rc)
3511 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003512
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3514 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003515 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3516 searchName, PATH_MAX, nls_codepage,
3517 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 name_len++; /* trailing null */
3519 name_len *= 2;
3520 pSMB->FileName[name_len] = 0;
3521 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003522 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 name_len = strnlen(searchName, PATH_MAX);
3524 name_len++; /* trailing null */
3525 strncpy(pSMB->FileName, searchName, name_len);
3526 }
3527
3528 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3529 pSMB->TotalDataCount = 0;
3530 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003531 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 pSMB->MaxDataCount = cpu_to_le16(4000);
3533 pSMB->MaxSetupCount = 0;
3534 pSMB->Reserved = 0;
3535 pSMB->Flags = 0;
3536 pSMB->Timeout = 0;
3537 pSMB->Reserved2 = 0;
3538 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003539 offsetof(struct smb_com_transaction2_qpi_req,
3540 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 pSMB->DataCount = 0;
3542 pSMB->DataOffset = 0;
3543 pSMB->SetupCount = 1;
3544 pSMB->Reserved3 = 0;
3545 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3546 byte_count = params + 1 /* pad */ ;
3547 pSMB->TotalParameterCount = cpu_to_le16(params);
3548 pSMB->ParameterCount = pSMB->TotalParameterCount;
3549 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3550 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003551 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 pSMB->ByteCount = cpu_to_le16(byte_count);
3553
3554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003556 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003558 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 } else {
3560 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003561
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003564 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 rc = -EIO; /* bad smb */
3566 else {
3567 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3568 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3569 rc = cifs_copy_posix_acl(acl_inf,
3570 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003571 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 }
3573 }
3574 cifs_buf_release(pSMB);
3575 if (rc == -EAGAIN)
3576 goto queryAclRetry;
3577 return rc;
3578}
3579
3580int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003581CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003582 const unsigned char *fileName,
3583 const char *local_acl, const int buflen,
3584 const int acl_type,
3585 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586{
3587 struct smb_com_transaction2_spi_req *pSMB = NULL;
3588 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3589 char *parm_data;
3590 int name_len;
3591 int rc = 0;
3592 int bytes_returned = 0;
3593 __u16 params, byte_count, data_count, param_offset, offset;
3594
Joe Perchesf96637b2013-05-04 22:12:25 -05003595 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596setAclRetry:
3597 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003598 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 if (rc)
3600 return rc;
3601 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3602 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003603 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3604 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 name_len++; /* trailing null */
3606 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003607 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 name_len = strnlen(fileName, PATH_MAX);
3609 name_len++; /* trailing null */
3610 strncpy(pSMB->FileName, fileName, name_len);
3611 }
3612 params = 6 + name_len;
3613 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003614 /* BB find max SMB size from sess */
3615 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 pSMB->MaxSetupCount = 0;
3617 pSMB->Reserved = 0;
3618 pSMB->Flags = 0;
3619 pSMB->Timeout = 0;
3620 pSMB->Reserved2 = 0;
3621 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003622 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 offset = param_offset + params;
3624 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3625 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3626
3627 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003628 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629
Steve French790fe572007-07-07 19:25:05 +00003630 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 rc = -EOPNOTSUPP;
3632 goto setACLerrorExit;
3633 }
3634 pSMB->DataOffset = cpu_to_le16(offset);
3635 pSMB->SetupCount = 1;
3636 pSMB->Reserved3 = 0;
3637 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3638 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3639 byte_count = 3 /* pad */ + params + data_count;
3640 pSMB->DataCount = cpu_to_le16(data_count);
3641 pSMB->TotalDataCount = pSMB->DataCount;
3642 pSMB->ParameterCount = cpu_to_le16(params);
3643 pSMB->TotalParameterCount = pSMB->ParameterCount;
3644 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003645 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 pSMB->ByteCount = cpu_to_le16(byte_count);
3647 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003648 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003649 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003650 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651
3652setACLerrorExit:
3653 cifs_buf_release(pSMB);
3654 if (rc == -EAGAIN)
3655 goto setAclRetry;
3656 return rc;
3657}
3658
Steve Frenchf654bac2005-04-28 22:41:04 -07003659/* BB fix tabs in this function FIXME BB */
3660int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003661CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003662 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003663{
Steve French50c2f752007-07-13 00:33:32 +00003664 int rc = 0;
3665 struct smb_t2_qfi_req *pSMB = NULL;
3666 struct smb_t2_qfi_rsp *pSMBr = NULL;
3667 int bytes_returned;
3668 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003669
Joe Perchesf96637b2013-05-04 22:12:25 -05003670 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003671 if (tcon == NULL)
3672 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003673
3674GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003675 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3676 (void **) &pSMBr);
3677 if (rc)
3678 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003679
Steve Frenchad7a2922008-02-07 23:25:02 +00003680 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003681 pSMB->t2.TotalDataCount = 0;
3682 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3683 /* BB find exact max data count below from sess structure BB */
3684 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3685 pSMB->t2.MaxSetupCount = 0;
3686 pSMB->t2.Reserved = 0;
3687 pSMB->t2.Flags = 0;
3688 pSMB->t2.Timeout = 0;
3689 pSMB->t2.Reserved2 = 0;
3690 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3691 Fid) - 4);
3692 pSMB->t2.DataCount = 0;
3693 pSMB->t2.DataOffset = 0;
3694 pSMB->t2.SetupCount = 1;
3695 pSMB->t2.Reserved3 = 0;
3696 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3697 byte_count = params + 1 /* pad */ ;
3698 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3699 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3700 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3701 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003702 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003703 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003704 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003705
Steve French790fe572007-07-07 19:25:05 +00003706 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3707 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3708 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003709 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003710 } else {
3711 /* decode response */
3712 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003713 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003714 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003715 /* If rc should we check for EOPNOSUPP and
3716 disable the srvino flag? or in caller? */
3717 rc = -EIO; /* bad smb */
3718 else {
3719 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3720 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3721 struct file_chattr_info *pfinfo;
3722 /* BB Do we need a cast or hash here ? */
3723 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003724 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003725 rc = -EIO;
3726 goto GetExtAttrOut;
3727 }
3728 pfinfo = (struct file_chattr_info *)
3729 (data_offset + (char *) &pSMBr->hdr.Protocol);
3730 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003731 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003732 }
3733 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003734GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003735 cifs_buf_release(pSMB);
3736 if (rc == -EAGAIN)
3737 goto GetExtAttrRetry;
3738 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003739}
3740
Steve Frenchf654bac2005-04-28 22:41:04 -07003741#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742
Jeff Layton79df1ba2010-12-06 12:52:08 -05003743#ifdef CONFIG_CIFS_ACL
3744/*
3745 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3746 * all NT TRANSACTS that we init here have total parm and data under about 400
3747 * bytes (to fit in small cifs buffer size), which is the case so far, it
3748 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3749 * returned setup area) and MaxParameterCount (returned parms size) must be set
3750 * by caller
3751 */
3752static int
3753smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003754 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003755 void **ret_buf)
3756{
3757 int rc;
3758 __u32 temp_offset;
3759 struct smb_com_ntransact_req *pSMB;
3760
3761 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3762 (void **)&pSMB);
3763 if (rc)
3764 return rc;
3765 *ret_buf = (void *)pSMB;
3766 pSMB->Reserved = 0;
3767 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3768 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003769 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003770 pSMB->ParameterCount = pSMB->TotalParameterCount;
3771 pSMB->DataCount = pSMB->TotalDataCount;
3772 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3773 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3774 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3775 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3776 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3777 pSMB->SubCommand = cpu_to_le16(sub_command);
3778 return 0;
3779}
3780
3781static int
3782validate_ntransact(char *buf, char **ppparm, char **ppdata,
3783 __u32 *pparmlen, __u32 *pdatalen)
3784{
3785 char *end_of_smb;
3786 __u32 data_count, data_offset, parm_count, parm_offset;
3787 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003788 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003789
3790 *pdatalen = 0;
3791 *pparmlen = 0;
3792
3793 if (buf == NULL)
3794 return -EINVAL;
3795
3796 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3797
Jeff Layton820a8032011-05-04 08:05:26 -04003798 bcc = get_bcc(&pSMBr->hdr);
3799 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003800 (char *)&pSMBr->ByteCount;
3801
3802 data_offset = le32_to_cpu(pSMBr->DataOffset);
3803 data_count = le32_to_cpu(pSMBr->DataCount);
3804 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3805 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3806
3807 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3808 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3809
3810 /* should we also check that parm and data areas do not overlap? */
3811 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003812 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003813 return -EINVAL;
3814 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003815 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003816 return -EINVAL;
3817 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003818 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003819 return -EINVAL;
3820 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003821 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3822 *ppdata, data_count, (data_count + *ppdata),
3823 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003824 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003825 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003826 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003827 return -EINVAL;
3828 }
3829 *pdatalen = data_count;
3830 *pparmlen = parm_count;
3831 return 0;
3832}
3833
Steve French0a4b92c2006-01-12 15:44:21 -08003834/* Get Security Descriptor (by handle) from remote server for a file or dir */
3835int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003836CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003837 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003838{
3839 int rc = 0;
3840 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003841 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003842 struct kvec iov[1];
3843
Joe Perchesf96637b2013-05-04 22:12:25 -05003844 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003845
Steve French630f3f0c2007-10-25 21:17:17 +00003846 *pbuflen = 0;
3847 *acl_inf = NULL;
3848
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003849 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003850 8 /* parm len */, tcon, (void **) &pSMB);
3851 if (rc)
3852 return rc;
3853
3854 pSMB->MaxParameterCount = cpu_to_le32(4);
3855 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3856 pSMB->MaxSetupCount = 0;
3857 pSMB->Fid = fid; /* file handle always le */
3858 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3859 CIFS_ACL_DACL);
3860 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003861 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003862 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003863 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003864
Steve Frencha761ac52007-10-18 21:45:27 +00003865 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003866 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003867 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003868 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003869 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003870 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003871 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003872 __u32 parm_len;
3873 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003874 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003875 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003876
3877/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003878 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003879 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003880 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003881 goto qsec_out;
3882 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3883
Joe Perchesf96637b2013-05-04 22:12:25 -05003884 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3885 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003886
3887 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3888 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003889 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003890 goto qsec_out;
3891 }
3892
3893/* BB check that data area is minimum length and as big as acl_len */
3894
Steve Frenchaf6f4612007-10-16 18:40:37 +00003895 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003896 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003897 cifs_dbg(VFS, "acl length %d does not match %d\n",
3898 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003899 if (*pbuflen > acl_len)
3900 *pbuflen = acl_len;
3901 }
Steve French0a4b92c2006-01-12 15:44:21 -08003902
Steve French630f3f0c2007-10-25 21:17:17 +00003903 /* check if buffer is big enough for the acl
3904 header followed by the smallest SID */
3905 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3906 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003907 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003908 rc = -EINVAL;
3909 *pbuflen = 0;
3910 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003911 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003912 if (*acl_inf == NULL) {
3913 *pbuflen = 0;
3914 rc = -ENOMEM;
3915 }
Steve French630f3f0c2007-10-25 21:17:17 +00003916 }
Steve French0a4b92c2006-01-12 15:44:21 -08003917 }
3918qsec_out:
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01003919 free_rsp_buf(buf_type, iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003920/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003921 return rc;
3922}
Steve French97837582007-12-31 07:47:21 +00003923
3924int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003925CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003926 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003927{
3928 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3929 int rc = 0;
3930 int bytes_returned = 0;
3931 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003932 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003933
3934setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003935 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003936 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003937 return rc;
Steve French97837582007-12-31 07:47:21 +00003938
3939 pSMB->MaxSetupCount = 0;
3940 pSMB->Reserved = 0;
3941
3942 param_count = 8;
3943 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3944 data_count = acllen;
3945 data_offset = param_offset + param_count;
3946 byte_count = 3 /* pad */ + param_count;
3947
3948 pSMB->DataCount = cpu_to_le32(data_count);
3949 pSMB->TotalDataCount = pSMB->DataCount;
3950 pSMB->MaxParameterCount = cpu_to_le32(4);
3951 pSMB->MaxDataCount = cpu_to_le32(16384);
3952 pSMB->ParameterCount = cpu_to_le32(param_count);
3953 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3954 pSMB->TotalParameterCount = pSMB->ParameterCount;
3955 pSMB->DataOffset = cpu_to_le32(data_offset);
3956 pSMB->SetupCount = 0;
3957 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3958 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3959
3960 pSMB->Fid = fid; /* file handle always le */
3961 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003962 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003963
3964 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003965 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3966 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003967 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003968 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003969 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003970
3971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3973
Joe Perchesf96637b2013-05-04 22:12:25 -05003974 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3975 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003976 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003977 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003978 cifs_buf_release(pSMB);
3979
3980 if (rc == -EAGAIN)
3981 goto setCifsAclRetry;
3982
3983 return (rc);
3984}
3985
Jeff Layton79df1ba2010-12-06 12:52:08 -05003986#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003987
Steve French6b8edfe2005-08-23 20:26:03 -07003988/* Legacy Query Path Information call for lookup to old servers such
3989 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003990int
3991SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3992 const char *search_name, FILE_ALL_INFO *data,
3993 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003994{
Steve Frenchad7a2922008-02-07 23:25:02 +00003995 QUERY_INFORMATION_REQ *pSMB;
3996 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003997 int rc = 0;
3998 int bytes_returned;
3999 int name_len;
4000
Joe Perchesf96637b2013-05-04 22:12:25 -05004001 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004002QInfRetry:
4003 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004004 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004005 if (rc)
4006 return rc;
4007
4008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4009 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004010 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004011 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004012 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004013 name_len++; /* trailing null */
4014 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004015 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004016 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004017 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004018 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004019 }
4020 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004021 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004022 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004023 pSMB->ByteCount = cpu_to_le16(name_len);
4024
4025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004027 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004028 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004029 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004030 struct timespec ts;
4031 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004032
4033 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004034 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004035 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004036 ts.tv_nsec = 0;
4037 ts.tv_sec = time;
4038 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004039 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4040 data->LastWriteTime = data->ChangeTime;
4041 data->LastAccessTime = 0;
4042 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004043 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004044 data->EndOfFile = data->AllocationSize;
4045 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004046 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004047 } else
4048 rc = -EIO; /* bad buffer passed in */
4049
4050 cifs_buf_release(pSMB);
4051
4052 if (rc == -EAGAIN)
4053 goto QInfRetry;
4054
4055 return rc;
4056}
4057
Jeff Laytonbcd53572010-02-12 07:44:16 -05004058int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004059CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004060 u16 netfid, FILE_ALL_INFO *pFindData)
4061{
4062 struct smb_t2_qfi_req *pSMB = NULL;
4063 struct smb_t2_qfi_rsp *pSMBr = NULL;
4064 int rc = 0;
4065 int bytes_returned;
4066 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004067
Jeff Laytonbcd53572010-02-12 07:44:16 -05004068QFileInfoRetry:
4069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4070 (void **) &pSMBr);
4071 if (rc)
4072 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004073
Jeff Laytonbcd53572010-02-12 07:44:16 -05004074 params = 2 /* level */ + 2 /* fid */;
4075 pSMB->t2.TotalDataCount = 0;
4076 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4077 /* BB find exact max data count below from sess structure BB */
4078 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4079 pSMB->t2.MaxSetupCount = 0;
4080 pSMB->t2.Reserved = 0;
4081 pSMB->t2.Flags = 0;
4082 pSMB->t2.Timeout = 0;
4083 pSMB->t2.Reserved2 = 0;
4084 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4085 Fid) - 4);
4086 pSMB->t2.DataCount = 0;
4087 pSMB->t2.DataOffset = 0;
4088 pSMB->t2.SetupCount = 1;
4089 pSMB->t2.Reserved3 = 0;
4090 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4091 byte_count = params + 1 /* pad */ ;
4092 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4093 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4094 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4095 pSMB->Pad = 0;
4096 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004097 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004098 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004099
4100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4102 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004103 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004104 } else { /* decode response */
4105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4106
4107 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4108 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004109 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004110 rc = -EIO; /* bad smb */
4111 else if (pFindData) {
4112 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4113 memcpy((char *) pFindData,
4114 (char *) &pSMBr->hdr.Protocol +
4115 data_offset, sizeof(FILE_ALL_INFO));
4116 } else
4117 rc = -ENOMEM;
4118 }
4119 cifs_buf_release(pSMB);
4120 if (rc == -EAGAIN)
4121 goto QFileInfoRetry;
4122
4123 return rc;
4124}
Steve French6b8edfe2005-08-23 20:26:03 -07004125
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004127CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004128 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004129 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004130 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004132 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 TRANSACTION2_QPI_REQ *pSMB = NULL;
4134 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4135 int rc = 0;
4136 int bytes_returned;
4137 int name_len;
4138 __u16 params, byte_count;
4139
Joe Perchesf96637b2013-05-04 22:12:25 -05004140 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141QPathInfoRetry:
4142 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4143 (void **) &pSMBr);
4144 if (rc)
4145 return rc;
4146
4147 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4148 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004149 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004150 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 name_len++; /* trailing null */
4152 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004153 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004154 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004156 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 }
4158
Steve French50c2f752007-07-13 00:33:32 +00004159 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 pSMB->TotalDataCount = 0;
4161 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004162 /* BB find exact max SMB PDU from sess structure BB */
4163 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 pSMB->MaxSetupCount = 0;
4165 pSMB->Reserved = 0;
4166 pSMB->Flags = 0;
4167 pSMB->Timeout = 0;
4168 pSMB->Reserved2 = 0;
4169 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004170 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 pSMB->DataCount = 0;
4172 pSMB->DataOffset = 0;
4173 pSMB->SetupCount = 1;
4174 pSMB->Reserved3 = 0;
4175 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4176 byte_count = params + 1 /* pad */ ;
4177 pSMB->TotalParameterCount = cpu_to_le16(params);
4178 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004179 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004180 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4181 else
4182 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004184 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 pSMB->ByteCount = cpu_to_le16(byte_count);
4186
4187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4189 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004190 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 } else { /* decode response */
4192 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4193
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004194 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4195 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004196 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004198 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004199 rc = -EIO; /* 24 or 26 expected but we do not read
4200 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004201 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004202 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004204
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004205 /*
4206 * On legacy responses we do not read the last field,
4207 * EAsize, fortunately since it varies by subdialect and
4208 * also note it differs on Set vs Get, ie two bytes or 4
4209 * bytes depending but we don't care here.
4210 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004211 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004212 size = sizeof(FILE_INFO_STANDARD);
4213 else
4214 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004215 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004216 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 } else
4218 rc = -ENOMEM;
4219 }
4220 cifs_buf_release(pSMB);
4221 if (rc == -EAGAIN)
4222 goto QPathInfoRetry;
4223
4224 return rc;
4225}
4226
4227int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004228CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004229 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4230{
4231 struct smb_t2_qfi_req *pSMB = NULL;
4232 struct smb_t2_qfi_rsp *pSMBr = NULL;
4233 int rc = 0;
4234 int bytes_returned;
4235 __u16 params, byte_count;
4236
4237UnixQFileInfoRetry:
4238 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4239 (void **) &pSMBr);
4240 if (rc)
4241 return rc;
4242
4243 params = 2 /* level */ + 2 /* fid */;
4244 pSMB->t2.TotalDataCount = 0;
4245 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4246 /* BB find exact max data count below from sess structure BB */
4247 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4248 pSMB->t2.MaxSetupCount = 0;
4249 pSMB->t2.Reserved = 0;
4250 pSMB->t2.Flags = 0;
4251 pSMB->t2.Timeout = 0;
4252 pSMB->t2.Reserved2 = 0;
4253 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4254 Fid) - 4);
4255 pSMB->t2.DataCount = 0;
4256 pSMB->t2.DataOffset = 0;
4257 pSMB->t2.SetupCount = 1;
4258 pSMB->t2.Reserved3 = 0;
4259 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4260 byte_count = params + 1 /* pad */ ;
4261 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4262 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4263 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4264 pSMB->Pad = 0;
4265 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004266 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004267 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004268
4269 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4270 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4271 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004272 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004273 } else { /* decode response */
4274 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4275
Jeff Layton820a8032011-05-04 08:05:26 -04004276 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004277 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 -05004278 rc = -EIO; /* bad smb */
4279 } else {
4280 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4281 memcpy((char *) pFindData,
4282 (char *) &pSMBr->hdr.Protocol +
4283 data_offset,
4284 sizeof(FILE_UNIX_BASIC_INFO));
4285 }
4286 }
4287
4288 cifs_buf_release(pSMB);
4289 if (rc == -EAGAIN)
4290 goto UnixQFileInfoRetry;
4291
4292 return rc;
4293}
4294
4295int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004296CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004298 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004299 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300{
4301/* SMB_QUERY_FILE_UNIX_BASIC */
4302 TRANSACTION2_QPI_REQ *pSMB = NULL;
4303 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4304 int rc = 0;
4305 int bytes_returned = 0;
4306 int name_len;
4307 __u16 params, byte_count;
4308
Joe Perchesf96637b2013-05-04 22:12:25 -05004309 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310UnixQPathInfoRetry:
4311 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4312 (void **) &pSMBr);
4313 if (rc)
4314 return rc;
4315
4316 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4317 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004318 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4319 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 name_len++; /* trailing null */
4321 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004322 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 name_len = strnlen(searchName, PATH_MAX);
4324 name_len++; /* trailing null */
4325 strncpy(pSMB->FileName, searchName, name_len);
4326 }
4327
Steve French50c2f752007-07-13 00:33:32 +00004328 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 pSMB->TotalDataCount = 0;
4330 pSMB->MaxParameterCount = cpu_to_le16(2);
4331 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004332 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 pSMB->MaxSetupCount = 0;
4334 pSMB->Reserved = 0;
4335 pSMB->Flags = 0;
4336 pSMB->Timeout = 0;
4337 pSMB->Reserved2 = 0;
4338 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004339 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 pSMB->DataCount = 0;
4341 pSMB->DataOffset = 0;
4342 pSMB->SetupCount = 1;
4343 pSMB->Reserved3 = 0;
4344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4345 byte_count = params + 1 /* pad */ ;
4346 pSMB->TotalParameterCount = cpu_to_le16(params);
4347 pSMB->ParameterCount = pSMB->TotalParameterCount;
4348 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4349 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004350 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 pSMB->ByteCount = cpu_to_le16(byte_count);
4352
4353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4355 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004356 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 } else { /* decode response */
4358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4359
Jeff Layton820a8032011-05-04 08:05:26 -04004360 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004361 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 -07004362 rc = -EIO; /* bad smb */
4363 } else {
4364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4365 memcpy((char *) pFindData,
4366 (char *) &pSMBr->hdr.Protocol +
4367 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004368 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 }
4370 }
4371 cifs_buf_release(pSMB);
4372 if (rc == -EAGAIN)
4373 goto UnixQPathInfoRetry;
4374
4375 return rc;
4376}
4377
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378/* xid, tcon, searchName and codepage are input parms, rest are returned */
4379int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004380CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004381 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004382 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004383 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384{
4385/* level 257 SMB_ */
4386 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4387 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004388 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 int rc = 0;
4390 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004391 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004393 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
Joe Perchesf96637b2013-05-04 22:12:25 -05004395 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396
4397findFirstRetry:
4398 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4399 (void **) &pSMBr);
4400 if (rc)
4401 return rc;
4402
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004403 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004404 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004405
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4407 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004408 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4409 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004410 /* We can not add the asterik earlier in case
4411 it got remapped to 0xF03A as if it were part of the
4412 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004414 if (msearch) {
4415 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4416 pSMB->FileName[name_len+1] = 0;
4417 pSMB->FileName[name_len+2] = '*';
4418 pSMB->FileName[name_len+3] = 0;
4419 name_len += 4; /* now the trailing null */
4420 /* null terminate just in case */
4421 pSMB->FileName[name_len] = 0;
4422 pSMB->FileName[name_len+1] = 0;
4423 name_len += 2;
4424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 } else { /* BB add check for overrun of SMB buf BB */
4426 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004428 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 free buffer exit; BB */
4430 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004431 if (msearch) {
4432 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4433 pSMB->FileName[name_len+1] = '*';
4434 pSMB->FileName[name_len+2] = 0;
4435 name_len += 3;
4436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 }
4438
4439 params = 12 + name_len /* includes null */ ;
4440 pSMB->TotalDataCount = 0; /* no EAs */
4441 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004442 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 pSMB->MaxSetupCount = 0;
4444 pSMB->Reserved = 0;
4445 pSMB->Flags = 0;
4446 pSMB->Timeout = 0;
4447 pSMB->Reserved2 = 0;
4448 byte_count = params + 1 /* pad */ ;
4449 pSMB->TotalParameterCount = cpu_to_le16(params);
4450 pSMB->ParameterCount = pSMB->TotalParameterCount;
4451 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004452 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4453 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 pSMB->DataCount = 0;
4455 pSMB->DataOffset = 0;
4456 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4457 pSMB->Reserved3 = 0;
4458 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4459 pSMB->SearchAttributes =
4460 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4461 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004462 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004463 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4465
4466 /* BB what should we set StorageType to? Does it matter? BB */
4467 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004468 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 pSMB->ByteCount = cpu_to_le16(byte_count);
4470
4471 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4472 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004473 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474
Steve French88274812006-03-09 22:21:45 +00004475 if (rc) {/* BB add logic to retry regular search if Unix search
4476 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004478 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004479
Steve French88274812006-03-09 22:21:45 +00004480 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481
4482 /* BB eventually could optimize out free and realloc of buf */
4483 /* for this case */
4484 if (rc == -EAGAIN)
4485 goto findFirstRetry;
4486 } else { /* decode response */
4487 /* BB remember to free buffer if error BB */
4488 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004489 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004490 unsigned int lnoff;
4491
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004493 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 else
Steve French4b18f2a2008-04-29 00:06:05 +00004495 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496
4497 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004498 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004499 psrch_inf->srch_entries_start =
4500 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4503 le16_to_cpu(pSMBr->t2.ParameterOffset));
4504
Steve French790fe572007-07-07 19:25:05 +00004505 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004506 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 else
Steve French4b18f2a2008-04-29 00:06:05 +00004508 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
Steve French50c2f752007-07-13 00:33:32 +00004510 psrch_inf->entries_in_buffer =
4511 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004512 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004514 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004515 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004516 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004517 psrch_inf->last_entry = NULL;
4518 return rc;
4519 }
4520
Steve French0752f152008-10-07 20:03:33 +00004521 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004522 lnoff;
4523
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004524 if (pnetfid)
4525 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 } else {
4527 cifs_buf_release(pSMB);
4528 }
4529 }
4530
4531 return rc;
4532}
4533
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004534int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4535 __u16 searchHandle, __u16 search_flags,
4536 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537{
4538 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4539 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004540 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 char *response_data;
4542 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004543 int bytes_returned;
4544 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 __u16 params, byte_count;
4546
Joe Perchesf96637b2013-05-04 22:12:25 -05004547 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
Steve French4b18f2a2008-04-29 00:06:05 +00004549 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 return -ENOENT;
4551
4552 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4553 (void **) &pSMBr);
4554 if (rc)
4555 return rc;
4556
Steve French50c2f752007-07-13 00:33:32 +00004557 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 byte_count = 0;
4559 pSMB->TotalDataCount = 0; /* no EAs */
4560 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004561 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 pSMB->MaxSetupCount = 0;
4563 pSMB->Reserved = 0;
4564 pSMB->Flags = 0;
4565 pSMB->Timeout = 0;
4566 pSMB->Reserved2 = 0;
4567 pSMB->ParameterOffset = cpu_to_le16(
4568 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4569 pSMB->DataCount = 0;
4570 pSMB->DataOffset = 0;
4571 pSMB->SetupCount = 1;
4572 pSMB->Reserved3 = 0;
4573 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4574 pSMB->SearchHandle = searchHandle; /* always kept as le */
4575 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004576 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4578 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004579 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580
4581 name_len = psrch_inf->resume_name_len;
4582 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004583 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4585 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004586 /* 14 byte parm len above enough for 2 byte null terminator */
4587 pSMB->ResumeFileName[name_len] = 0;
4588 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 } else {
4590 rc = -EINVAL;
4591 goto FNext2_err_exit;
4592 }
4593 byte_count = params + 1 /* pad */ ;
4594 pSMB->TotalParameterCount = cpu_to_le16(params);
4595 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004596 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004598
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4600 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004601 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 if (rc) {
4603 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004604 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004605 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004606 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004608 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 } else { /* decode response */
4610 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004611
Steve French790fe572007-07-07 19:25:05 +00004612 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004613 unsigned int lnoff;
4614
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 /* BB fixme add lock for file (srch_info) struct here */
4616 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004617 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 else
Steve French4b18f2a2008-04-29 00:06:05 +00004619 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 response_data = (char *) &pSMBr->hdr.Protocol +
4621 le16_to_cpu(pSMBr->t2.ParameterOffset);
4622 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4623 response_data = (char *)&pSMBr->hdr.Protocol +
4624 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004625 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004626 cifs_small_buf_release(
4627 psrch_inf->ntwrk_buf_start);
4628 else
4629 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 psrch_inf->srch_entries_start = response_data;
4631 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004632 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004633 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004634 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 else
Steve French4b18f2a2008-04-29 00:06:05 +00004636 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004637 psrch_inf->entries_in_buffer =
4638 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 psrch_inf->index_of_last_entry +=
4640 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004641 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004642 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004643 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004644 psrch_inf->last_entry = NULL;
4645 return rc;
4646 } else
4647 psrch_inf->last_entry =
4648 psrch_inf->srch_entries_start + lnoff;
4649
Joe Perchesf96637b2013-05-04 22:12:25 -05004650/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4651 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652
4653 /* BB fixme add unlock here */
4654 }
4655
4656 }
4657
4658 /* BB On error, should we leave previous search buf (and count and
4659 last entry fields) intact or free the previous one? */
4660
4661 /* Note: On -EAGAIN error only caller can retry on handle based calls
4662 since file handle passed in no longer valid */
4663FNext2_err_exit:
4664 if (rc != 0)
4665 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 return rc;
4667}
4668
4669int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004670CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004671 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672{
4673 int rc = 0;
4674 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675
Joe Perchesf96637b2013-05-04 22:12:25 -05004676 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4678
4679 /* no sense returning error if session restarted
4680 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004681 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 return 0;
4683 if (rc)
4684 return rc;
4685
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 pSMB->FileID = searchHandle;
4687 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004688 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004689 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004690 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004691
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004692 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693
4694 /* Since session is dead, search handle closed on server already */
4695 if (rc == -EAGAIN)
4696 rc = 0;
4697
4698 return rc;
4699}
4700
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004702CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004703 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004704 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705{
4706 int rc = 0;
4707 TRANSACTION2_QPI_REQ *pSMB = NULL;
4708 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4709 int name_len, bytes_returned;
4710 __u16 params, byte_count;
4711
Joe Perchesf96637b2013-05-04 22:12:25 -05004712 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004713 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004714 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715
4716GetInodeNumberRetry:
4717 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004718 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 if (rc)
4720 return rc;
4721
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4723 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004724 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004725 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004726 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 name_len++; /* trailing null */
4728 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004729 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004730 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004732 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 }
4734
4735 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4736 pSMB->TotalDataCount = 0;
4737 pSMB->MaxParameterCount = cpu_to_le16(2);
4738 /* BB find exact max data count below from sess structure BB */
4739 pSMB->MaxDataCount = cpu_to_le16(4000);
4740 pSMB->MaxSetupCount = 0;
4741 pSMB->Reserved = 0;
4742 pSMB->Flags = 0;
4743 pSMB->Timeout = 0;
4744 pSMB->Reserved2 = 0;
4745 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004746 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 pSMB->DataCount = 0;
4748 pSMB->DataOffset = 0;
4749 pSMB->SetupCount = 1;
4750 pSMB->Reserved3 = 0;
4751 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4752 byte_count = params + 1 /* pad */ ;
4753 pSMB->TotalParameterCount = cpu_to_le16(params);
4754 pSMB->ParameterCount = pSMB->TotalParameterCount;
4755 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4756 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004757 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 pSMB->ByteCount = cpu_to_le16(byte_count);
4759
4760 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4761 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4762 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004763 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 } else {
4765 /* decode response */
4766 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004768 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 /* If rc should we check for EOPNOSUPP and
4770 disable the srvino flag? or in caller? */
4771 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004772 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4774 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004775 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004777 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004778 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 rc = -EIO;
4780 goto GetInodeNumOut;
4781 }
4782 pfinfo = (struct file_internal_info *)
4783 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004784 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 }
4786 }
4787GetInodeNumOut:
4788 cifs_buf_release(pSMB);
4789 if (rc == -EAGAIN)
4790 goto GetInodeNumberRetry;
4791 return rc;
4792}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793
Igor Mammedovfec45852008-05-16 13:06:30 +04004794/* parses DFS refferal V3 structure
4795 * caller is responsible for freeing target_nodes
4796 * returns:
4797 * on success - 0
4798 * on failure - errno
4799 */
4800static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004801parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004802 unsigned int *num_of_nodes,
4803 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004804 const struct nls_table *nls_codepage, int remap,
4805 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004806{
4807 int i, rc = 0;
4808 char *data_end;
4809 bool is_unicode;
4810 struct dfs_referral_level_3 *ref;
4811
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004812 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4813 is_unicode = true;
4814 else
4815 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004816 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4817
4818 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004819 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4820 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004821 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004822 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004823 }
4824
4825 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004826 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004827 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4828 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004829 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004830 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004831 }
4832
4833 /* get the upper boundary of the resp buffer */
4834 data_end = (char *)(&(pSMBr->PathConsumed)) +
4835 le16_to_cpu(pSMBr->t2.DataCount);
4836
Joe Perchesf96637b2013-05-04 22:12:25 -05004837 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4838 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004839
Joe Perchesf96637b2013-05-04 22:12:25 -05004840 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4841 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004842 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004843 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004844 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004845 }
4846
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004847 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004848 for (i = 0; i < *num_of_nodes; i++) {
4849 char *temp;
4850 int max_len;
4851 struct dfs_info3_param *node = (*target_nodes)+i;
4852
Steve French0e0d2cf2009-05-01 05:27:32 +00004853 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004854 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004855 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4856 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004857 if (tmp == NULL) {
4858 rc = -ENOMEM;
4859 goto parse_DFS_referrals_exit;
4860 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004861 cifsConvertToUTF16((__le16 *) tmp, searchName,
4862 PATH_MAX, nls_codepage, remap);
4863 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004864 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004865 nls_codepage);
4866 kfree(tmp);
4867 } else
4868 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4869
Igor Mammedovfec45852008-05-16 13:06:30 +04004870 node->server_type = le16_to_cpu(ref->ServerType);
4871 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4872
4873 /* copy DfsPath */
4874 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4875 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004876 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4877 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004878 if (!node->path_name) {
4879 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004880 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004881 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004882
4883 /* copy link target UNC */
4884 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4885 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004886 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4887 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004888 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004889 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004890 goto parse_DFS_referrals_exit;
4891 }
4892
4893 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004894 }
4895
Steve Frencha1fe78f2008-05-16 18:48:38 +00004896parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004897 if (rc) {
4898 free_dfs_info_array(*target_nodes, *num_of_nodes);
4899 *target_nodes = NULL;
4900 *num_of_nodes = 0;
4901 }
4902 return rc;
4903}
4904
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004906CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004907 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004908 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004909 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910{
4911/* TRANS2_GET_DFS_REFERRAL */
4912 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4913 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 int rc = 0;
4915 int bytes_returned;
4916 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004918 *num_of_nodes = 0;
4919 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920
Joe Perchesf96637b2013-05-04 22:12:25 -05004921 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 if (ses == NULL)
4923 return -ENODEV;
4924getDFSRetry:
4925 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4926 (void **) &pSMBr);
4927 if (rc)
4928 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004929
4930 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004931 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004932 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 pSMB->hdr.Tid = ses->ipc_tid;
4934 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004935 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004937 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939
4940 if (ses->capabilities & CAP_UNICODE) {
4941 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4942 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004943 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004944 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004945 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 name_len++; /* trailing null */
4947 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004948 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004949 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004951 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 }
4953
Dan Carpenter65c3b202015-04-30 17:30:24 +03004954 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004955 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004956
Steve French50c2f752007-07-13 00:33:32 +00004957 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004958
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 params = 2 /* level */ + name_len /*includes null */ ;
4960 pSMB->TotalDataCount = 0;
4961 pSMB->DataCount = 0;
4962 pSMB->DataOffset = 0;
4963 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004964 /* BB find exact max SMB PDU from sess structure BB */
4965 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966 pSMB->MaxSetupCount = 0;
4967 pSMB->Reserved = 0;
4968 pSMB->Flags = 0;
4969 pSMB->Timeout = 0;
4970 pSMB->Reserved2 = 0;
4971 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004972 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 pSMB->SetupCount = 1;
4974 pSMB->Reserved3 = 0;
4975 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4976 byte_count = params + 3 /* pad */ ;
4977 pSMB->ParameterCount = cpu_to_le16(params);
4978 pSMB->TotalParameterCount = pSMB->ParameterCount;
4979 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004980 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 pSMB->ByteCount = cpu_to_le16(byte_count);
4982
4983 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4985 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004986 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004987 goto GetDFSRefExit;
4988 }
4989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004991 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004992 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004993 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004994 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004996
Joe Perchesf96637b2013-05-04 22:12:25 -05004997 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4998 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004999
5000 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00005001 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04005002 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04005003 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04005004
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00005006 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007
5008 if (rc == -EAGAIN)
5009 goto getDFSRetry;
5010
5011 return rc;
5012}
5013
Steve French20962432005-09-21 22:05:57 -07005014/* Query File System Info such as free space to old servers such as Win 9x */
5015int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005016SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5017 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005018{
5019/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5020 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5021 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5022 FILE_SYSTEM_ALLOC_INFO *response_data;
5023 int rc = 0;
5024 int bytes_returned = 0;
5025 __u16 params, byte_count;
5026
Joe Perchesf96637b2013-05-04 22:12:25 -05005027 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005028oldQFSInfoRetry:
5029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5030 (void **) &pSMBr);
5031 if (rc)
5032 return rc;
Steve French20962432005-09-21 22:05:57 -07005033
5034 params = 2; /* level */
5035 pSMB->TotalDataCount = 0;
5036 pSMB->MaxParameterCount = cpu_to_le16(2);
5037 pSMB->MaxDataCount = cpu_to_le16(1000);
5038 pSMB->MaxSetupCount = 0;
5039 pSMB->Reserved = 0;
5040 pSMB->Flags = 0;
5041 pSMB->Timeout = 0;
5042 pSMB->Reserved2 = 0;
5043 byte_count = params + 1 /* pad */ ;
5044 pSMB->TotalParameterCount = cpu_to_le16(params);
5045 pSMB->ParameterCount = pSMB->TotalParameterCount;
5046 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5047 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5048 pSMB->DataCount = 0;
5049 pSMB->DataOffset = 0;
5050 pSMB->SetupCount = 1;
5051 pSMB->Reserved3 = 0;
5052 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5053 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005054 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005055 pSMB->ByteCount = cpu_to_le16(byte_count);
5056
5057 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5058 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5059 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005060 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005061 } else { /* decode response */
5062 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5063
Jeff Layton820a8032011-05-04 08:05:26 -04005064 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005065 rc = -EIO; /* bad smb */
5066 else {
5067 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005068 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005069 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005070
Steve French50c2f752007-07-13 00:33:32 +00005071 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005072 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5073 FSData->f_bsize =
5074 le16_to_cpu(response_data->BytesPerSector) *
5075 le32_to_cpu(response_data->
5076 SectorsPerAllocationUnit);
5077 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005078 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005079 FSData->f_bfree = FSData->f_bavail =
5080 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005081 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5082 (unsigned long long)FSData->f_blocks,
5083 (unsigned long long)FSData->f_bfree,
5084 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005085 }
5086 }
5087 cifs_buf_release(pSMB);
5088
5089 if (rc == -EAGAIN)
5090 goto oldQFSInfoRetry;
5091
5092 return rc;
5093}
5094
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005096CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5097 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098{
5099/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5100 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5101 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5102 FILE_SYSTEM_INFO *response_data;
5103 int rc = 0;
5104 int bytes_returned = 0;
5105 __u16 params, byte_count;
5106
Joe Perchesf96637b2013-05-04 22:12:25 -05005107 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108QFSInfoRetry:
5109 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5110 (void **) &pSMBr);
5111 if (rc)
5112 return rc;
5113
5114 params = 2; /* level */
5115 pSMB->TotalDataCount = 0;
5116 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005117 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 pSMB->MaxSetupCount = 0;
5119 pSMB->Reserved = 0;
5120 pSMB->Flags = 0;
5121 pSMB->Timeout = 0;
5122 pSMB->Reserved2 = 0;
5123 byte_count = params + 1 /* pad */ ;
5124 pSMB->TotalParameterCount = cpu_to_le16(params);
5125 pSMB->ParameterCount = pSMB->TotalParameterCount;
5126 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005127 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 pSMB->DataCount = 0;
5129 pSMB->DataOffset = 0;
5130 pSMB->SetupCount = 1;
5131 pSMB->Reserved3 = 0;
5132 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5133 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005134 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 pSMB->ByteCount = cpu_to_le16(byte_count);
5136
5137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5139 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005140 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005142 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
Jeff Layton820a8032011-05-04 08:05:26 -04005144 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 rc = -EIO; /* bad smb */
5146 else {
5147 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148
5149 response_data =
5150 (FILE_SYSTEM_INFO
5151 *) (((char *) &pSMBr->hdr.Protocol) +
5152 data_offset);
5153 FSData->f_bsize =
5154 le32_to_cpu(response_data->BytesPerSector) *
5155 le32_to_cpu(response_data->
5156 SectorsPerAllocationUnit);
5157 FSData->f_blocks =
5158 le64_to_cpu(response_data->TotalAllocationUnits);
5159 FSData->f_bfree = FSData->f_bavail =
5160 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005161 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5162 (unsigned long long)FSData->f_blocks,
5163 (unsigned long long)FSData->f_bfree,
5164 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 }
5166 }
5167 cifs_buf_release(pSMB);
5168
5169 if (rc == -EAGAIN)
5170 goto QFSInfoRetry;
5171
5172 return rc;
5173}
5174
5175int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005176CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177{
5178/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5179 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5180 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5181 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5182 int rc = 0;
5183 int bytes_returned = 0;
5184 __u16 params, byte_count;
5185
Joe Perchesf96637b2013-05-04 22:12:25 -05005186 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187QFSAttributeRetry:
5188 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5189 (void **) &pSMBr);
5190 if (rc)
5191 return rc;
5192
5193 params = 2; /* level */
5194 pSMB->TotalDataCount = 0;
5195 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005196 /* BB find exact max SMB PDU from sess structure BB */
5197 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 pSMB->MaxSetupCount = 0;
5199 pSMB->Reserved = 0;
5200 pSMB->Flags = 0;
5201 pSMB->Timeout = 0;
5202 pSMB->Reserved2 = 0;
5203 byte_count = params + 1 /* pad */ ;
5204 pSMB->TotalParameterCount = cpu_to_le16(params);
5205 pSMB->ParameterCount = pSMB->TotalParameterCount;
5206 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005207 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 pSMB->DataCount = 0;
5209 pSMB->DataOffset = 0;
5210 pSMB->SetupCount = 1;
5211 pSMB->Reserved3 = 0;
5212 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5213 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005214 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 pSMB->ByteCount = cpu_to_le16(byte_count);
5216
5217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5219 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005220 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 } else { /* decode response */
5222 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5223
Jeff Layton820a8032011-05-04 08:05:26 -04005224 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005225 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 rc = -EIO; /* bad smb */
5227 } else {
5228 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5229 response_data =
5230 (FILE_SYSTEM_ATTRIBUTE_INFO
5231 *) (((char *) &pSMBr->hdr.Protocol) +
5232 data_offset);
5233 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005234 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 }
5236 }
5237 cifs_buf_release(pSMB);
5238
5239 if (rc == -EAGAIN)
5240 goto QFSAttributeRetry;
5241
5242 return rc;
5243}
5244
5245int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005246CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247{
5248/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5249 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5250 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5251 FILE_SYSTEM_DEVICE_INFO *response_data;
5252 int rc = 0;
5253 int bytes_returned = 0;
5254 __u16 params, byte_count;
5255
Joe Perchesf96637b2013-05-04 22:12:25 -05005256 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257QFSDeviceRetry:
5258 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5259 (void **) &pSMBr);
5260 if (rc)
5261 return rc;
5262
5263 params = 2; /* level */
5264 pSMB->TotalDataCount = 0;
5265 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005266 /* BB find exact max SMB PDU from sess structure BB */
5267 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 pSMB->MaxSetupCount = 0;
5269 pSMB->Reserved = 0;
5270 pSMB->Flags = 0;
5271 pSMB->Timeout = 0;
5272 pSMB->Reserved2 = 0;
5273 byte_count = params + 1 /* pad */ ;
5274 pSMB->TotalParameterCount = cpu_to_le16(params);
5275 pSMB->ParameterCount = pSMB->TotalParameterCount;
5276 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005277 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278
5279 pSMB->DataCount = 0;
5280 pSMB->DataOffset = 0;
5281 pSMB->SetupCount = 1;
5282 pSMB->Reserved3 = 0;
5283 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5284 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005285 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 pSMB->ByteCount = cpu_to_le16(byte_count);
5287
5288 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5289 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5290 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005291 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 } else { /* decode response */
5293 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5294
Jeff Layton820a8032011-05-04 08:05:26 -04005295 if (rc || get_bcc(&pSMBr->hdr) <
5296 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 rc = -EIO; /* bad smb */
5298 else {
5299 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5300 response_data =
Steve French737b7582005-04-28 22:41:06 -07005301 (FILE_SYSTEM_DEVICE_INFO *)
5302 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 data_offset);
5304 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005305 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 }
5307 }
5308 cifs_buf_release(pSMB);
5309
5310 if (rc == -EAGAIN)
5311 goto QFSDeviceRetry;
5312
5313 return rc;
5314}
5315
5316int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005317CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318{
5319/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5320 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5321 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5322 FILE_SYSTEM_UNIX_INFO *response_data;
5323 int rc = 0;
5324 int bytes_returned = 0;
5325 __u16 params, byte_count;
5326
Joe Perchesf96637b2013-05-04 22:12:25 -05005327 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005329 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5330 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 if (rc)
5332 return rc;
5333
5334 params = 2; /* level */
5335 pSMB->TotalDataCount = 0;
5336 pSMB->DataCount = 0;
5337 pSMB->DataOffset = 0;
5338 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005339 /* BB find exact max SMB PDU from sess structure BB */
5340 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 pSMB->MaxSetupCount = 0;
5342 pSMB->Reserved = 0;
5343 pSMB->Flags = 0;
5344 pSMB->Timeout = 0;
5345 pSMB->Reserved2 = 0;
5346 byte_count = params + 1 /* pad */ ;
5347 pSMB->ParameterCount = cpu_to_le16(params);
5348 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005349 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5350 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 pSMB->SetupCount = 1;
5352 pSMB->Reserved3 = 0;
5353 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005355 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 pSMB->ByteCount = cpu_to_le16(byte_count);
5357
5358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5360 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005361 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 } else { /* decode response */
5363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5364
Jeff Layton820a8032011-05-04 08:05:26 -04005365 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 rc = -EIO; /* bad smb */
5367 } else {
5368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5369 response_data =
5370 (FILE_SYSTEM_UNIX_INFO
5371 *) (((char *) &pSMBr->hdr.Protocol) +
5372 data_offset);
5373 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005374 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 }
5376 }
5377 cifs_buf_release(pSMB);
5378
5379 if (rc == -EAGAIN)
5380 goto QFSUnixRetry;
5381
5382
5383 return rc;
5384}
5385
Jeremy Allisonac670552005-06-22 17:26:35 -07005386int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005387CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005388{
5389/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5390 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5391 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5392 int rc = 0;
5393 int bytes_returned = 0;
5394 __u16 params, param_offset, offset, byte_count;
5395
Joe Perchesf96637b2013-05-04 22:12:25 -05005396 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005397SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005398 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005399 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5400 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005401 if (rc)
5402 return rc;
5403
5404 params = 4; /* 2 bytes zero followed by info level. */
5405 pSMB->MaxSetupCount = 0;
5406 pSMB->Reserved = 0;
5407 pSMB->Flags = 0;
5408 pSMB->Timeout = 0;
5409 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005410 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5411 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005412 offset = param_offset + params;
5413
5414 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005415 /* BB find exact max SMB PDU from sess structure BB */
5416 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005417 pSMB->SetupCount = 1;
5418 pSMB->Reserved3 = 0;
5419 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5420 byte_count = 1 /* pad */ + params + 12;
5421
5422 pSMB->DataCount = cpu_to_le16(12);
5423 pSMB->ParameterCount = cpu_to_le16(params);
5424 pSMB->TotalDataCount = pSMB->DataCount;
5425 pSMB->TotalParameterCount = pSMB->ParameterCount;
5426 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5427 pSMB->DataOffset = cpu_to_le16(offset);
5428
5429 /* Params. */
5430 pSMB->FileNum = 0;
5431 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5432
5433 /* Data. */
5434 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5435 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5436 pSMB->ClientUnixCap = cpu_to_le64(cap);
5437
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005438 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005439 pSMB->ByteCount = cpu_to_le16(byte_count);
5440
5441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5443 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005444 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005445 } else { /* decode response */
5446 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005447 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005448 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005449 }
5450 cifs_buf_release(pSMB);
5451
5452 if (rc == -EAGAIN)
5453 goto SETFSUnixRetry;
5454
5455 return rc;
5456}
5457
5458
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
5460int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005461CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005462 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463{
5464/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5465 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5466 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5467 FILE_SYSTEM_POSIX_INFO *response_data;
5468 int rc = 0;
5469 int bytes_returned = 0;
5470 __u16 params, byte_count;
5471
Joe Perchesf96637b2013-05-04 22:12:25 -05005472 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473QFSPosixRetry:
5474 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5475 (void **) &pSMBr);
5476 if (rc)
5477 return rc;
5478
5479 params = 2; /* level */
5480 pSMB->TotalDataCount = 0;
5481 pSMB->DataCount = 0;
5482 pSMB->DataOffset = 0;
5483 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005484 /* BB find exact max SMB PDU from sess structure BB */
5485 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 pSMB->MaxSetupCount = 0;
5487 pSMB->Reserved = 0;
5488 pSMB->Flags = 0;
5489 pSMB->Timeout = 0;
5490 pSMB->Reserved2 = 0;
5491 byte_count = params + 1 /* pad */ ;
5492 pSMB->ParameterCount = cpu_to_le16(params);
5493 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005494 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5495 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 pSMB->SetupCount = 1;
5497 pSMB->Reserved3 = 0;
5498 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5499 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005500 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 pSMB->ByteCount = cpu_to_le16(byte_count);
5502
5503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5505 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005506 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 } else { /* decode response */
5508 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5509
Jeff Layton820a8032011-05-04 08:05:26 -04005510 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 rc = -EIO; /* bad smb */
5512 } else {
5513 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5514 response_data =
5515 (FILE_SYSTEM_POSIX_INFO
5516 *) (((char *) &pSMBr->hdr.Protocol) +
5517 data_offset);
5518 FSData->f_bsize =
5519 le32_to_cpu(response_data->BlockSize);
5520 FSData->f_blocks =
5521 le64_to_cpu(response_data->TotalBlocks);
5522 FSData->f_bfree =
5523 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005524 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 FSData->f_bavail = FSData->f_bfree;
5526 } else {
5527 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005528 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 }
Steve French790fe572007-07-07 19:25:05 +00005530 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005532 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005533 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005535 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 }
5537 }
5538 cifs_buf_release(pSMB);
5539
5540 if (rc == -EAGAIN)
5541 goto QFSPosixRetry;
5542
5543 return rc;
5544}
5545
5546
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005547/*
5548 * We can not use write of zero bytes trick to set file size due to need for
5549 * large file support. Also note that this SetPathInfo is preferred to
5550 * SetFileInfo based method in next routine which is only needed to work around
5551 * a sharing violation bugin Samba which this routine can run into.
5552 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005554CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005555 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5556 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557{
5558 struct smb_com_transaction2_spi_req *pSMB = NULL;
5559 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5560 struct file_end_of_file_info *parm_data;
5561 int name_len;
5562 int rc = 0;
5563 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005564 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005565
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 __u16 params, byte_count, data_count, param_offset, offset;
5567
Joe Perchesf96637b2013-05-04 22:12:25 -05005568 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569SetEOFRetry:
5570 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5571 (void **) &pSMBr);
5572 if (rc)
5573 return rc;
5574
5575 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5576 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005577 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5578 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 name_len++; /* trailing null */
5580 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005581 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005582 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005584 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 }
5586 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005587 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005589 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 pSMB->MaxSetupCount = 0;
5591 pSMB->Reserved = 0;
5592 pSMB->Flags = 0;
5593 pSMB->Timeout = 0;
5594 pSMB->Reserved2 = 0;
5595 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005596 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005598 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005599 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5600 pSMB->InformationLevel =
5601 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5602 else
5603 pSMB->InformationLevel =
5604 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5605 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5607 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005608 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 else
5610 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005611 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 }
5613
5614 parm_data =
5615 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5616 offset);
5617 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5618 pSMB->DataOffset = cpu_to_le16(offset);
5619 pSMB->SetupCount = 1;
5620 pSMB->Reserved3 = 0;
5621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5622 byte_count = 3 /* pad */ + params + data_count;
5623 pSMB->DataCount = cpu_to_le16(data_count);
5624 pSMB->TotalDataCount = pSMB->DataCount;
5625 pSMB->ParameterCount = cpu_to_le16(params);
5626 pSMB->TotalParameterCount = pSMB->ParameterCount;
5627 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005628 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 parm_data->FileSize = cpu_to_le64(size);
5630 pSMB->ByteCount = cpu_to_le16(byte_count);
5631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005633 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005634 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
5636 cifs_buf_release(pSMB);
5637
5638 if (rc == -EAGAIN)
5639 goto SetEOFRetry;
5640
5641 return rc;
5642}
5643
5644int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005645CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5646 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647{
5648 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 struct file_end_of_file_info *parm_data;
5650 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 __u16 params, param_offset, offset, byte_count, count;
5652
Joe Perchesf96637b2013-05-04 22:12:25 -05005653 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5654 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005655 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5656
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 if (rc)
5658 return rc;
5659
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005660 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5661 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005662
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 params = 6;
5664 pSMB->MaxSetupCount = 0;
5665 pSMB->Reserved = 0;
5666 pSMB->Flags = 0;
5667 pSMB->Timeout = 0;
5668 pSMB->Reserved2 = 0;
5669 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5670 offset = param_offset + params;
5671
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 count = sizeof(struct file_end_of_file_info);
5673 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005674 /* BB find exact max SMB PDU from sess structure BB */
5675 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 pSMB->SetupCount = 1;
5677 pSMB->Reserved3 = 0;
5678 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5679 byte_count = 3 /* pad */ + params + count;
5680 pSMB->DataCount = cpu_to_le16(count);
5681 pSMB->ParameterCount = cpu_to_le16(params);
5682 pSMB->TotalDataCount = pSMB->DataCount;
5683 pSMB->TotalParameterCount = pSMB->ParameterCount;
5684 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5685 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005686 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5687 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 pSMB->DataOffset = cpu_to_le16(offset);
5689 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005690 pSMB->Fid = cfile->fid.netfid;
5691 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5693 pSMB->InformationLevel =
5694 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5695 else
5696 pSMB->InformationLevel =
5697 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005698 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5700 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005701 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702 else
5703 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005704 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705 }
5706 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005707 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005709 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005711 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5712 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713 }
5714
Steve French50c2f752007-07-13 00:33:32 +00005715 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 since file handle passed in no longer valid */
5717
5718 return rc;
5719}
5720
Steve French50c2f752007-07-13 00:33:32 +00005721/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 an open handle, rather than by pathname - this is awkward due to
5723 potential access conflicts on the open, but it is unavoidable for these
5724 old servers since the only other choice is to go from 100 nanosecond DCE
5725 time and resort to the original setpathinfo level which takes the ancient
5726 DOS time format with 2 second granularity */
5727int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005728CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005729 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730{
5731 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 char *data_offset;
5733 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 __u16 params, param_offset, offset, byte_count, count;
5735
Joe Perchesf96637b2013-05-04 22:12:25 -05005736 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005737 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5738
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 if (rc)
5740 return rc;
5741
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005742 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5743 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005744
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 params = 6;
5746 pSMB->MaxSetupCount = 0;
5747 pSMB->Reserved = 0;
5748 pSMB->Flags = 0;
5749 pSMB->Timeout = 0;
5750 pSMB->Reserved2 = 0;
5751 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5752 offset = param_offset + params;
5753
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005754 data_offset = (char *)pSMB +
5755 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756
Steve French26f57362007-08-30 22:09:15 +00005757 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005759 /* BB find max SMB PDU from sess */
5760 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 pSMB->SetupCount = 1;
5762 pSMB->Reserved3 = 0;
5763 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5764 byte_count = 3 /* pad */ + params + count;
5765 pSMB->DataCount = cpu_to_le16(count);
5766 pSMB->ParameterCount = cpu_to_le16(params);
5767 pSMB->TotalDataCount = pSMB->DataCount;
5768 pSMB->TotalParameterCount = pSMB->ParameterCount;
5769 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5770 pSMB->DataOffset = cpu_to_le16(offset);
5771 pSMB->Fid = fid;
5772 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5773 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5774 else
5775 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5776 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005777 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005779 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005780 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005781 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005782 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5783 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
Steve French50c2f752007-07-13 00:33:32 +00005785 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786 since file handle passed in no longer valid */
5787
5788 return rc;
5789}
5790
Jeff Layton6d22f092008-09-23 11:48:35 -04005791int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005792CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005793 bool delete_file, __u16 fid, __u32 pid_of_opener)
5794{
5795 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5796 char *data_offset;
5797 int rc = 0;
5798 __u16 params, param_offset, offset, byte_count, count;
5799
Joe Perchesf96637b2013-05-04 22:12:25 -05005800 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005801 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5802
5803 if (rc)
5804 return rc;
5805
5806 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5807 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5808
5809 params = 6;
5810 pSMB->MaxSetupCount = 0;
5811 pSMB->Reserved = 0;
5812 pSMB->Flags = 0;
5813 pSMB->Timeout = 0;
5814 pSMB->Reserved2 = 0;
5815 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5816 offset = param_offset + params;
5817
5818 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5819
5820 count = 1;
5821 pSMB->MaxParameterCount = cpu_to_le16(2);
5822 /* BB find max SMB PDU from sess */
5823 pSMB->MaxDataCount = cpu_to_le16(1000);
5824 pSMB->SetupCount = 1;
5825 pSMB->Reserved3 = 0;
5826 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5827 byte_count = 3 /* pad */ + params + count;
5828 pSMB->DataCount = cpu_to_le16(count);
5829 pSMB->ParameterCount = cpu_to_le16(params);
5830 pSMB->TotalDataCount = pSMB->DataCount;
5831 pSMB->TotalParameterCount = pSMB->ParameterCount;
5832 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5833 pSMB->DataOffset = cpu_to_le16(offset);
5834 pSMB->Fid = fid;
5835 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5836 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005837 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005838 pSMB->ByteCount = cpu_to_le16(byte_count);
5839 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005840 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005841 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005842 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005843
5844 return rc;
5845}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846
5847int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005848CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005849 const char *fileName, const FILE_BASIC_INFO *data,
5850 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851{
5852 TRANSACTION2_SPI_REQ *pSMB = NULL;
5853 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5854 int name_len;
5855 int rc = 0;
5856 int bytes_returned = 0;
5857 char *data_offset;
5858 __u16 params, param_offset, offset, byte_count, count;
5859
Joe Perchesf96637b2013-05-04 22:12:25 -05005860 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861
5862SetTimesRetry:
5863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5864 (void **) &pSMBr);
5865 if (rc)
5866 return rc;
5867
5868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5869 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005870 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5871 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 name_len++; /* trailing null */
5873 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005874 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 name_len = strnlen(fileName, PATH_MAX);
5876 name_len++; /* trailing null */
5877 strncpy(pSMB->FileName, fileName, name_len);
5878 }
5879
5880 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005881 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005883 /* BB find max SMB PDU from sess structure BB */
5884 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 pSMB->MaxSetupCount = 0;
5886 pSMB->Reserved = 0;
5887 pSMB->Flags = 0;
5888 pSMB->Timeout = 0;
5889 pSMB->Reserved2 = 0;
5890 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005891 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 offset = param_offset + params;
5893 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5894 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5895 pSMB->DataOffset = cpu_to_le16(offset);
5896 pSMB->SetupCount = 1;
5897 pSMB->Reserved3 = 0;
5898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5899 byte_count = 3 /* pad */ + params + count;
5900
5901 pSMB->DataCount = cpu_to_le16(count);
5902 pSMB->ParameterCount = cpu_to_le16(params);
5903 pSMB->TotalDataCount = pSMB->DataCount;
5904 pSMB->TotalParameterCount = pSMB->ParameterCount;
5905 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5906 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5907 else
5908 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5909 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005910 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005911 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 pSMB->ByteCount = cpu_to_le16(byte_count);
5913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005915 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005916 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917
5918 cifs_buf_release(pSMB);
5919
5920 if (rc == -EAGAIN)
5921 goto SetTimesRetry;
5922
5923 return rc;
5924}
5925
5926/* Can not be used to set time stamps yet (due to old DOS time format) */
5927/* Can be used to set attributes */
5928#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5929 handling it anyway and NT4 was what we thought it would be needed for
5930 Do not delete it until we prove whether needed for Win9x though */
5931int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005932CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 __u16 dos_attrs, const struct nls_table *nls_codepage)
5934{
5935 SETATTR_REQ *pSMB = NULL;
5936 SETATTR_RSP *pSMBr = NULL;
5937 int rc = 0;
5938 int bytes_returned;
5939 int name_len;
5940
Joe Perchesf96637b2013-05-04 22:12:25 -05005941 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942
5943SetAttrLgcyRetry:
5944 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5945 (void **) &pSMBr);
5946 if (rc)
5947 return rc;
5948
5949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5950 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005951 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5952 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 name_len++; /* trailing null */
5954 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005955 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 name_len = strnlen(fileName, PATH_MAX);
5957 name_len++; /* trailing null */
5958 strncpy(pSMB->fileName, fileName, name_len);
5959 }
5960 pSMB->attr = cpu_to_le16(dos_attrs);
5961 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005962 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005966 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005967 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968
5969 cifs_buf_release(pSMB);
5970
5971 if (rc == -EAGAIN)
5972 goto SetAttrLgcyRetry;
5973
5974 return rc;
5975}
5976#endif /* temporarily unneeded SetAttr legacy function */
5977
Jeff Layton654cf142009-07-09 20:02:49 -04005978static void
5979cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5980 const struct cifs_unix_set_info_args *args)
5981{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005982 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005983 u64 mode = args->mode;
5984
Eric W. Biederman49418b22013-02-06 00:57:56 -08005985 if (uid_valid(args->uid))
5986 uid = from_kuid(&init_user_ns, args->uid);
5987 if (gid_valid(args->gid))
5988 gid = from_kgid(&init_user_ns, args->gid);
5989
Jeff Layton654cf142009-07-09 20:02:49 -04005990 /*
5991 * Samba server ignores set of file size to zero due to bugs in some
5992 * older clients, but we should be precise - we use SetFileSize to
5993 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005994 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005995 * zero instead of -1 here
5996 */
5997 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5998 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5999 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
6000 data_offset->LastAccessTime = cpu_to_le64(args->atime);
6001 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08006002 data_offset->Uid = cpu_to_le64(uid);
6003 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04006004 /* better to leave device as zero when it is */
6005 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
6006 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
6007 data_offset->Permissions = cpu_to_le64(mode);
6008
6009 if (S_ISREG(mode))
6010 data_offset->Type = cpu_to_le32(UNIX_FILE);
6011 else if (S_ISDIR(mode))
6012 data_offset->Type = cpu_to_le32(UNIX_DIR);
6013 else if (S_ISLNK(mode))
6014 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6015 else if (S_ISCHR(mode))
6016 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6017 else if (S_ISBLK(mode))
6018 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6019 else if (S_ISFIFO(mode))
6020 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6021 else if (S_ISSOCK(mode))
6022 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6023}
6024
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006026CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006027 const struct cifs_unix_set_info_args *args,
6028 u16 fid, u32 pid_of_opener)
6029{
6030 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006031 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006032 int rc = 0;
6033 u16 params, param_offset, offset, byte_count, count;
6034
Joe Perchesf96637b2013-05-04 22:12:25 -05006035 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006036 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6037
6038 if (rc)
6039 return rc;
6040
6041 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6042 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6043
6044 params = 6;
6045 pSMB->MaxSetupCount = 0;
6046 pSMB->Reserved = 0;
6047 pSMB->Flags = 0;
6048 pSMB->Timeout = 0;
6049 pSMB->Reserved2 = 0;
6050 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6051 offset = param_offset + params;
6052
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006053 data_offset = (char *)pSMB +
6054 offsetof(struct smb_hdr, Protocol) + offset;
6055
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006056 count = sizeof(FILE_UNIX_BASIC_INFO);
6057
6058 pSMB->MaxParameterCount = cpu_to_le16(2);
6059 /* BB find max SMB PDU from sess */
6060 pSMB->MaxDataCount = cpu_to_le16(1000);
6061 pSMB->SetupCount = 1;
6062 pSMB->Reserved3 = 0;
6063 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6064 byte_count = 3 /* pad */ + params + count;
6065 pSMB->DataCount = cpu_to_le16(count);
6066 pSMB->ParameterCount = cpu_to_le16(params);
6067 pSMB->TotalDataCount = pSMB->DataCount;
6068 pSMB->TotalParameterCount = pSMB->ParameterCount;
6069 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6070 pSMB->DataOffset = cpu_to_le16(offset);
6071 pSMB->Fid = fid;
6072 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6073 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006074 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006075 pSMB->ByteCount = cpu_to_le16(byte_count);
6076
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006077 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006078
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006079 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006080 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006081 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6082 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006083
6084 /* Note: On -EAGAIN error only caller can retry on handle based calls
6085 since file handle passed in no longer valid */
6086
6087 return rc;
6088}
6089
6090int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006091CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006092 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006093 const struct cifs_unix_set_info_args *args,
6094 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095{
6096 TRANSACTION2_SPI_REQ *pSMB = NULL;
6097 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6098 int name_len;
6099 int rc = 0;
6100 int bytes_returned = 0;
6101 FILE_UNIX_BASIC_INFO *data_offset;
6102 __u16 params, param_offset, offset, count, byte_count;
6103
Joe Perchesf96637b2013-05-04 22:12:25 -05006104 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105setPermsRetry:
6106 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6107 (void **) &pSMBr);
6108 if (rc)
6109 return rc;
6110
6111 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6112 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006113 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006114 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 name_len++; /* trailing null */
6116 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006117 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006118 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006120 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121 }
6122
6123 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006124 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006126 /* BB find max SMB PDU from sess structure BB */
6127 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128 pSMB->MaxSetupCount = 0;
6129 pSMB->Reserved = 0;
6130 pSMB->Flags = 0;
6131 pSMB->Timeout = 0;
6132 pSMB->Reserved2 = 0;
6133 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006134 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 offset = param_offset + params;
6136 data_offset =
6137 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6138 offset);
6139 memset(data_offset, 0, count);
6140 pSMB->DataOffset = cpu_to_le16(offset);
6141 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6142 pSMB->SetupCount = 1;
6143 pSMB->Reserved3 = 0;
6144 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6145 byte_count = 3 /* pad */ + params + count;
6146 pSMB->ParameterCount = cpu_to_le16(params);
6147 pSMB->DataCount = cpu_to_le16(count);
6148 pSMB->TotalParameterCount = pSMB->ParameterCount;
6149 pSMB->TotalDataCount = pSMB->DataCount;
6150 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6151 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006152 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006153
Jeff Layton654cf142009-07-09 20:02:49 -04006154 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155
6156 pSMB->ByteCount = cpu_to_le16(byte_count);
6157 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6158 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006159 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006160 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161
Steve French0d817bc2008-05-22 02:02:03 +00006162 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 if (rc == -EAGAIN)
6164 goto setPermsRetry;
6165 return rc;
6166}
6167
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006169/*
6170 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6171 * function used by listxattr and getxattr type calls. When ea_name is set,
6172 * it looks for that attribute name and stuffs that value into the EAData
6173 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6174 * buffer. In both cases, the return value is either the length of the
6175 * resulting data or a negative error code. If EAData is a NULL pointer then
6176 * the data isn't copied to it, but the length is returned.
6177 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006179CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006180 const unsigned char *searchName, const unsigned char *ea_name,
6181 char *EAData, size_t buf_size,
6182 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183{
6184 /* BB assumes one setup word */
6185 TRANSACTION2_QPI_REQ *pSMB = NULL;
6186 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6187 int rc = 0;
6188 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006189 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006190 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006191 struct fea *temp_fea;
6192 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006193 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006194 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006195 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196
Joe Perchesf96637b2013-05-04 22:12:25 -05006197 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198QAllEAsRetry:
6199 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6200 (void **) &pSMBr);
6201 if (rc)
6202 return rc;
6203
6204 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006205 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006206 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6207 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006208 list_len++; /* trailing null */
6209 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006211 list_len = strnlen(searchName, PATH_MAX);
6212 list_len++; /* trailing null */
6213 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 }
6215
Jeff Layton6e462b92010-02-10 16:18:26 -05006216 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 pSMB->TotalDataCount = 0;
6218 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006219 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006220 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 pSMB->MaxSetupCount = 0;
6222 pSMB->Reserved = 0;
6223 pSMB->Flags = 0;
6224 pSMB->Timeout = 0;
6225 pSMB->Reserved2 = 0;
6226 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006227 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228 pSMB->DataCount = 0;
6229 pSMB->DataOffset = 0;
6230 pSMB->SetupCount = 1;
6231 pSMB->Reserved3 = 0;
6232 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6233 byte_count = params + 1 /* pad */ ;
6234 pSMB->TotalParameterCount = cpu_to_le16(params);
6235 pSMB->ParameterCount = pSMB->TotalParameterCount;
6236 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6237 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006238 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239 pSMB->ByteCount = cpu_to_le16(byte_count);
6240
6241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6242 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6243 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006244 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006245 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006247
6248
6249 /* BB also check enough total bytes returned */
6250 /* BB we need to improve the validity checking
6251 of these trans2 responses */
6252
6253 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006254 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006255 rc = -EIO; /* bad smb */
6256 goto QAllEAsOut;
6257 }
6258
6259 /* check that length of list is not more than bcc */
6260 /* check that each entry does not go beyond length
6261 of list */
6262 /* check that each element of each entry does not
6263 go beyond end of list */
6264 /* validate_trans2_offsets() */
6265 /* BB check if start of smb + data_offset > &bcc+ bcc */
6266
6267 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6268 ea_response_data = (struct fealist *)
6269 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6270
Jeff Layton6e462b92010-02-10 16:18:26 -05006271 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006272 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006273 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006274 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006275 /* didn't find the named attribute */
6276 if (ea_name)
6277 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006278 goto QAllEAsOut;
6279 }
6280
Jeff Layton0cd126b2010-02-10 16:18:26 -05006281 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006282 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006283 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006284 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006285 rc = -EIO;
6286 goto QAllEAsOut;
6287 }
6288
Jeff Laytonf0d38682010-02-10 16:18:26 -05006289 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006290 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006291 temp_fea = ea_response_data->list;
6292 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006293 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006294 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006295 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006296
Jeff Layton6e462b92010-02-10 16:18:26 -05006297 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006298 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006299 /* make sure we can read name_len and value_len */
6300 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006301 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006302 rc = -EIO;
6303 goto QAllEAsOut;
6304 }
6305
6306 name_len = temp_fea->name_len;
6307 value_len = le16_to_cpu(temp_fea->value_len);
6308 list_len -= name_len + 1 + value_len;
6309 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006310 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006311 rc = -EIO;
6312 goto QAllEAsOut;
6313 }
6314
Jeff Layton31c05192010-02-10 16:18:26 -05006315 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006316 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006317 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006318 temp_ptr += name_len + 1;
6319 rc = value_len;
6320 if (buf_size == 0)
6321 goto QAllEAsOut;
6322 if ((size_t)value_len > buf_size) {
6323 rc = -ERANGE;
6324 goto QAllEAsOut;
6325 }
6326 memcpy(EAData, temp_ptr, value_len);
6327 goto QAllEAsOut;
6328 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006329 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006330 /* account for prefix user. and trailing null */
6331 rc += (5 + 1 + name_len);
6332 if (rc < (int) buf_size) {
6333 memcpy(EAData, "user.", 5);
6334 EAData += 5;
6335 memcpy(EAData, temp_ptr, name_len);
6336 EAData += name_len;
6337 /* null terminate name */
6338 *EAData = 0;
6339 ++EAData;
6340 } else if (buf_size == 0) {
6341 /* skip copy - calc size only */
6342 } else {
6343 /* stop before overrun buffer */
6344 rc = -ERANGE;
6345 break;
6346 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006347 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006348 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006349 temp_fea = (struct fea *)temp_ptr;
6350 }
6351
Jeff Layton31c05192010-02-10 16:18:26 -05006352 /* didn't find the named attribute */
6353 if (ea_name)
6354 rc = -ENODATA;
6355
Jeff Laytonf0d38682010-02-10 16:18:26 -05006356QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006357 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 if (rc == -EAGAIN)
6359 goto QAllEAsRetry;
6360
6361 return (ssize_t)rc;
6362}
6363
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006365CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6366 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006367 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6368 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369{
6370 struct smb_com_transaction2_spi_req *pSMB = NULL;
6371 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6372 struct fealist *parm_data;
6373 int name_len;
6374 int rc = 0;
6375 int bytes_returned = 0;
6376 __u16 params, param_offset, byte_count, offset, count;
6377
Joe Perchesf96637b2013-05-04 22:12:25 -05006378 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379SetEARetry:
6380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6381 (void **) &pSMBr);
6382 if (rc)
6383 return rc;
6384
6385 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6386 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006387 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6388 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389 name_len++; /* trailing null */
6390 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006391 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 name_len = strnlen(fileName, PATH_MAX);
6393 name_len++; /* trailing null */
6394 strncpy(pSMB->FileName, fileName, name_len);
6395 }
6396
6397 params = 6 + name_len;
6398
6399 /* done calculating parms using name_len of file name,
6400 now use name_len to calculate length of ea name
6401 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006402 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 name_len = 0;
6404 else
Steve French50c2f752007-07-13 00:33:32 +00006405 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006407 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006409 /* BB find max SMB PDU from sess */
6410 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411 pSMB->MaxSetupCount = 0;
6412 pSMB->Reserved = 0;
6413 pSMB->Flags = 0;
6414 pSMB->Timeout = 0;
6415 pSMB->Reserved2 = 0;
6416 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006417 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006418 offset = param_offset + params;
6419 pSMB->InformationLevel =
6420 cpu_to_le16(SMB_SET_FILE_EA);
6421
Arnd Bergmann4bf53b52018-02-02 16:48:47 +01006422 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006423 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6424 pSMB->DataOffset = cpu_to_le16(offset);
6425 pSMB->SetupCount = 1;
6426 pSMB->Reserved3 = 0;
6427 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6428 byte_count = 3 /* pad */ + params + count;
6429 pSMB->DataCount = cpu_to_le16(count);
6430 parm_data->list_len = cpu_to_le32(count);
6431 parm_data->list[0].EA_flags = 0;
6432 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006433 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006435 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006436 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437 parm_data->list[0].name[name_len] = 0;
6438 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6439 /* caller ensures that ea_value_len is less than 64K but
6440 we need to ensure that it fits within the smb */
6441
Steve French50c2f752007-07-13 00:33:32 +00006442 /*BB add length check to see if it would fit in
6443 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006444 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6445 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006446 memcpy(parm_data->list[0].name+name_len+1,
6447 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448
6449 pSMB->TotalDataCount = pSMB->DataCount;
6450 pSMB->ParameterCount = cpu_to_le16(params);
6451 pSMB->TotalParameterCount = pSMB->ParameterCount;
6452 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006453 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454 pSMB->ByteCount = cpu_to_le16(byte_count);
6455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006457 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006458 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459
6460 cifs_buf_release(pSMB);
6461
6462 if (rc == -EAGAIN)
6463 goto SetEARetry;
6464
6465 return rc;
6466}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006467#endif
Steve French0eff0e22011-02-24 05:39:23 +00006468
6469#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6470/*
6471 * Years ago the kernel added a "dnotify" function for Samba server,
6472 * to allow network clients (such as Windows) to display updated
6473 * lists of files in directory listings automatically when
6474 * files are added by one user when another user has the
6475 * same directory open on their desktop. The Linux cifs kernel
6476 * client hooked into the kernel side of this interface for
6477 * the same reason, but ironically when the VFS moved from
6478 * "dnotify" to "inotify" it became harder to plug in Linux
6479 * network file system clients (the most obvious use case
6480 * for notify interfaces is when multiple users can update
6481 * the contents of the same directory - exactly what network
6482 * file systems can do) although the server (Samba) could
6483 * still use it. For the short term we leave the worker
6484 * function ifdeffed out (below) until inotify is fixed
6485 * in the VFS to make it easier to plug in network file
6486 * system clients. If inotify turns out to be permanently
6487 * incompatible for network fs clients, we could instead simply
6488 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6489 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006490int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006491 const int notify_subdirs, const __u16 netfid,
6492 __u32 filter, struct file *pfile, int multishot,
6493 const struct nls_table *nls_codepage)
6494{
6495 int rc = 0;
6496 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6497 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6498 struct dir_notify_req *dnotify_req;
6499 int bytes_returned;
6500
Joe Perchesf96637b2013-05-04 22:12:25 -05006501 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006502 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6503 (void **) &pSMBr);
6504 if (rc)
6505 return rc;
6506
6507 pSMB->TotalParameterCount = 0 ;
6508 pSMB->TotalDataCount = 0;
6509 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006510 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006511 pSMB->MaxSetupCount = 4;
6512 pSMB->Reserved = 0;
6513 pSMB->ParameterOffset = 0;
6514 pSMB->DataCount = 0;
6515 pSMB->DataOffset = 0;
6516 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6517 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6518 pSMB->ParameterCount = pSMB->TotalParameterCount;
6519 if (notify_subdirs)
6520 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6521 pSMB->Reserved2 = 0;
6522 pSMB->CompletionFilter = cpu_to_le32(filter);
6523 pSMB->Fid = netfid; /* file handle always le */
6524 pSMB->ByteCount = 0;
6525
6526 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6527 (struct smb_hdr *)pSMBr, &bytes_returned,
6528 CIFS_ASYNC_OP);
6529 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006530 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006531 } else {
6532 /* Add file to outstanding requests */
6533 /* BB change to kmem cache alloc */
6534 dnotify_req = kmalloc(
6535 sizeof(struct dir_notify_req),
6536 GFP_KERNEL);
6537 if (dnotify_req) {
6538 dnotify_req->Pid = pSMB->hdr.Pid;
6539 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6540 dnotify_req->Mid = pSMB->hdr.Mid;
6541 dnotify_req->Tid = pSMB->hdr.Tid;
6542 dnotify_req->Uid = pSMB->hdr.Uid;
6543 dnotify_req->netfid = netfid;
6544 dnotify_req->pfile = pfile;
6545 dnotify_req->filter = filter;
6546 dnotify_req->multishot = multishot;
6547 spin_lock(&GlobalMid_Lock);
6548 list_add_tail(&dnotify_req->lhead,
6549 &GlobalDnotifyReqList);
6550 spin_unlock(&GlobalMid_Lock);
6551 } else
6552 rc = -ENOMEM;
6553 }
6554 cifs_buf_release(pSMB);
6555 return rc;
6556}
6557#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */