blob: 609ce335e6ac0683a7eaf13dce2ebe3f5fe062d8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080038#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500101 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Steve French3afca262016-09-22 18:58:16 -0500107 spin_unlock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500142 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500166 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 rc = cifs_setup_session(0, ses, nls_codepage);
184
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 goto out;
189 }
190
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400191 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500194 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
Jeff Layton9162ab22009-09-03 12:07:17 -0400199 atomic_inc(&tconInfoReconnectCount);
200
201 /* tell server Unix caps we support */
202 if (ses->capabilities & CAP_UNIX)
203 reset_cifs_unix_caps(0, tcon, NULL, NULL);
204
205 /*
206 * Removed call to reopen open files here. It is safer (and faster) to
207 * reopen files one at a time as needed in read and write.
208 *
209 * FIXME: what about file locks? don't we need to reclaim them ASAP?
210 */
211
212out:
213 /*
214 * Check if handle based operation so we know whether we can continue
215 * or not without returning to caller to reset file handle
216 */
217 switch (smb_command) {
218 case SMB_COM_READ_ANDX:
219 case SMB_COM_WRITE_ANDX:
220 case SMB_COM_CLOSE:
221 case SMB_COM_FIND_CLOSE2:
222 case SMB_COM_LOCKING_ANDX:
223 rc = -EAGAIN;
224 }
225
226 unload_nls(nls_codepage);
227 return rc;
228}
229
Steve Frenchad7a2922008-02-07 23:25:02 +0000230/* Allocate and return pointer to an SMB request buffer, and set basic
231 SMB information in the SMB header. If the return code is zero, this
232 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int
Steve French96daf2b2011-05-27 04:34:02 +0000234small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000235 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Jeff Laytonf5695992010-09-29 15:27:08 -0400237 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Jeff Layton9162ab22009-09-03 12:07:17 -0400239 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000240 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 return rc;
242
243 *request_buf = cifs_small_buf_get();
244 if (*request_buf == NULL) {
245 /* BB should we add a retry in here if not a writepage? */
246 return -ENOMEM;
247 }
248
Steve French63135e02007-07-17 17:34:02 +0000249 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000250 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Steve French790fe572007-07-07 19:25:05 +0000252 if (tcon != NULL)
253 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700254
Jeff Laytonf5695992010-09-29 15:27:08 -0400255 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000256}
257
Steve French12b3b8f2006-02-09 21:12:47 +0000258int
Steve French50c2f752007-07-13 00:33:32 +0000259small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000260 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000261{
262 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000263 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000264
Steve French5815449d2006-02-14 01:36:20 +0000265 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000266 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000267 return rc;
268
Steve French04fdabe2006-02-10 05:52:50 +0000269 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400270 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000271 if (ses->capabilities & CAP_UNICODE)
272 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000273 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000274 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
275
276 /* uid, tid can stay at zero as set in header assemble */
277
Steve French50c2f752007-07-13 00:33:32 +0000278 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000279 this function is used after 1st of session setup requests */
280
281 return rc;
282}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284/* If the return code is zero, this function must fill in request_buf pointer */
285static int
Steve French96daf2b2011-05-27 04:34:02 +0000286__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400287 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 *request_buf = cifs_buf_get();
290 if (*request_buf == NULL) {
291 /* BB should we add a retry in here if not a writepage? */
292 return -ENOMEM;
293 }
294 /* Although the original thought was we needed the response buf for */
295 /* potential retries of smb operations it turns out we can determine */
296 /* from the mid flags when the request buffer can be resent without */
297 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000298 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000299 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000302 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Steve French790fe572007-07-07 19:25:05 +0000304 if (tcon != NULL)
305 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700306
Jeff Laytonf5695992010-09-29 15:27:08 -0400307 return 0;
308}
309
310/* If the return code is zero, this function must fill in request_buf pointer */
311static int
Steve French96daf2b2011-05-27 04:34:02 +0000312smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400313 void **request_buf, void **response_buf)
314{
315 int rc;
316
317 rc = cifs_reconnect_tcon(tcon, smb_command);
318 if (rc)
319 return rc;
320
321 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
322}
323
324static int
Steve French96daf2b2011-05-27 04:34:02 +0000325smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400326 void **request_buf, void **response_buf)
327{
328 if (tcon->ses->need_reconnect || tcon->need_reconnect)
329 return -EHOSTDOWN;
330
331 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Steve French50c2f752007-07-13 00:33:32 +0000334static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Jeff Layton12df83c2011-01-20 13:36:51 -0500336 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Jeff Layton12df83c2011-01-20 13:36:51 -0500338 /* check for plausible wct */
339 if (pSMB->hdr.WordCount < 10)
340 goto vt2_err;
341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500343 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
344 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
345 goto vt2_err;
346
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
348 if (total_size >= 512)
349 goto vt2_err;
350
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400351 /* check that bcc is at least as big as parms + data, and that it is
352 * less than negotiated smb buffer
353 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500354 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
355 if (total_size > get_bcc(&pSMB->hdr) ||
356 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
357 goto vt2_err;
358
359 return 0;
360vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000361 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500363 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
Jeff Layton690c5222011-01-20 13:36:51 -0500365
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400366static int
Jeff Layton3f618222013-06-12 19:52:14 -0500367decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400368{
369 int rc = 0;
370 u16 count;
371 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500372 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400373
374 count = get_bcc(&pSMBr->hdr);
375 if (count < SMB1_CLIENT_GUID_SIZE)
376 return -EIO;
377
378 spin_lock(&cifs_tcp_ses_lock);
379 if (server->srv_count > 1) {
380 spin_unlock(&cifs_tcp_ses_lock);
381 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
382 cifs_dbg(FYI, "server UID changed\n");
383 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
384 }
385 } else {
386 spin_unlock(&cifs_tcp_ses_lock);
387 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
388 }
389
390 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500391 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400392 } else {
393 count -= SMB1_CLIENT_GUID_SIZE;
394 rc = decode_negTokenInit(
395 pSMBr->u.extended_response.SecurityBlob, count, server);
396 if (rc != 1)
397 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400398 }
399
400 return 0;
401}
402
Jeff Layton9ddec562013-05-26 07:00:58 -0400403int
Jeff Layton38d77c52013-05-26 07:01:00 -0400404cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400405{
Jeff Layton502858822013-06-27 12:45:00 -0400406 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
407 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400408 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
409
410 /*
411 * Is signing required by mnt options? If not then check
412 * global_secflags to see if it is there.
413 */
414 if (!mnt_sign_required)
415 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
416 CIFSSEC_MUST_SIGN);
417
418 /*
419 * If signing is required then it's automatically enabled too,
420 * otherwise, check to see if the secflags allow it.
421 */
422 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
423 (global_secflags & CIFSSEC_MAY_SIGN);
424
425 /* If server requires signing, does client allow it? */
426 if (srv_sign_required) {
427 if (!mnt_sign_enabled) {
428 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
429 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400430 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400431 server->sign = true;
432 }
433
434 /* If client requires signing, does server allow it? */
435 if (mnt_sign_required) {
436 if (!srv_sign_enabled) {
437 cifs_dbg(VFS, "Server does not support signing!");
438 return -ENOTSUPP;
439 }
440 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400441 }
442
443 return 0;
444}
445
Jeff Layton2190eca2013-05-26 07:00:57 -0400446#ifdef CONFIG_CIFS_WEAK_PW_HASH
447static int
Jeff Layton3f618222013-06-12 19:52:14 -0500448decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400449{
450 __s16 tmp;
451 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
452
453 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
454 return -EOPNOTSUPP;
455
Jeff Layton2190eca2013-05-26 07:00:57 -0400456 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
457 server->maxReq = min_t(unsigned int,
458 le16_to_cpu(rsp->MaxMpxCount),
459 cifs_max_pending);
460 set_credits(server, server->maxReq);
461 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400462 /* even though we do not use raw we might as well set this
463 accurately, in case we ever find a need for it */
464 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
465 server->max_rw = 0xFF00;
466 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
467 } else {
468 server->max_rw = 0;/* do not need to use raw anyway */
469 server->capabilities = CAP_MPX_MODE;
470 }
471 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
472 if (tmp == -1) {
473 /* OS/2 often does not set timezone therefore
474 * we must use server time to calc time zone.
475 * Could deviate slightly from the right zone.
476 * Smallest defined timezone difference is 15 minutes
477 * (i.e. Nepal). Rounding up/down is done to match
478 * this requirement.
479 */
480 int val, seconds, remain, result;
481 struct timespec ts, utc;
482 utc = CURRENT_TIME;
483 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
484 rsp->SrvTime.Time, 0);
485 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
486 (int)ts.tv_sec, (int)utc.tv_sec,
487 (int)(utc.tv_sec - ts.tv_sec));
488 val = (int)(utc.tv_sec - ts.tv_sec);
489 seconds = abs(val);
490 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
491 remain = seconds % MIN_TZ_ADJ;
492 if (remain >= (MIN_TZ_ADJ / 2))
493 result += MIN_TZ_ADJ;
494 if (val < 0)
495 result = -result;
496 server->timeAdj = result;
497 } else {
498 server->timeAdj = (int)tmp;
499 server->timeAdj *= 60; /* also in seconds */
500 }
501 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
502
503
504 /* BB get server time for time conversions and add
505 code to use it and timezone since this is not UTC */
506
507 if (rsp->EncryptionKeyLength ==
508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
509 memcpy(server->cryptkey, rsp->EncryptionKey,
510 CIFS_CRYPTO_KEY_SIZE);
511 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
512 return -EIO; /* need cryptkey unless plain text */
513 }
514
515 cifs_dbg(FYI, "LANMAN negotiated\n");
516 return 0;
517}
518#else
519static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500520decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400521{
522 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
523 return -EOPNOTSUPP;
524}
525#endif
526
Jeff Layton91934002013-05-26 07:00:58 -0400527static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500528should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400529{
Jeff Layton3f618222013-06-12 19:52:14 -0500530 switch (sectype) {
531 case RawNTLMSSP:
532 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400533 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500534 case Unspecified:
535 if (global_secflags &
536 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
537 return true;
538 /* Fallthrough */
539 default:
540 return false;
541 }
Jeff Layton91934002013-05-26 07:00:58 -0400542}
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400545CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 NEGOTIATE_REQ *pSMB;
548 NEGOTIATE_RSP *pSMBr;
549 int rc = 0;
550 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000551 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400552 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 u16 count;
554
Jeff Layton3534b852013-05-24 07:41:01 -0400555 if (!server) {
556 WARN(1, "%s: server is NULL!\n", __func__);
557 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 }
Jeff Layton3534b852013-05-24 07:41:01 -0400559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
561 (void **) &pSMB, (void **) &pSMBr);
562 if (rc)
563 return rc;
Steve French750d1152006-06-27 06:28:30 +0000564
Pavel Shilovsky88257362012-05-23 14:01:59 +0400565 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000566 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000567
Jeff Layton3f618222013-06-12 19:52:14 -0500568 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400569 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000570 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
571 }
Steve French50c2f752007-07-13 00:33:32 +0000572
Steve French39798772006-05-31 22:40:51 +0000573 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000574 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000575 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
576 count += strlen(protocols[i].name) + 1;
577 /* null at end of source and target buffers anyway */
578 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000579 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 pSMB->ByteCount = cpu_to_le16(count);
581
582 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
583 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000584 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000585 goto neg_err_exit;
586
Jeff Layton9bf67e52010-04-24 07:57:46 -0400587 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500588 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000589 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400590 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000591 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000592 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000593 could not negotiate a common dialect */
594 rc = -EOPNOTSUPP;
595 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000596 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400597 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500598 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400599 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000600 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000601 /* unknown wct */
602 rc = -EOPNOTSUPP;
603 goto neg_err_exit;
604 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400605 /* else wct == 17, NTLM or better */
606
Steve French96daf2b2011-05-27 04:34:02 +0000607 server->sec_mode = pSMBr->SecurityMode;
608 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500609 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000610
Steve French254e55e2006-06-04 05:53:15 +0000611 /* one byte, so no need to convert this or EncryptionKeyLen from
612 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300613 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
614 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400615 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000616 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400617 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000618 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500619 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000620 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000621 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
622 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400623
Jeff Laytone598d1d82013-05-26 07:00:59 -0400624 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
625 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500626 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000627 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100628 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
629 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400630 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500631 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400632 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000633 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400634 } else {
635 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000636 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400637 }
Steve French254e55e2006-06-04 05:53:15 +0000638
639signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400640 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400641 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000642neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700643 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000644
Joe Perchesf96637b2013-05-04 22:12:25 -0500645 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 return rc;
647}
648
649int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400650CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651{
652 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Joe Perchesf96637b2013-05-04 22:12:25 -0500655 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500656
657 /* BB: do we need to check this? These should never be NULL. */
658 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
659 return -EIO;
660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500662 * No need to return error on this operation if tid invalidated and
663 * closed on server already e.g. due to tcp session crashing. Also,
664 * the tcon is no longer on the list, so no need to take lock before
665 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 */
Steve French268875b2009-06-25 00:29:21 +0000667 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000668 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Steve French50c2f752007-07-13 00:33:32 +0000670 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700671 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500672 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return rc;
Steve French133672e2007-11-13 22:41:37 +0000674
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400675 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700676 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500678 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Steve French50c2f752007-07-13 00:33:32 +0000680 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (rc == -EAGAIN)
683 rc = 0;
684
685 return rc;
686}
687
Jeff Layton766fdbb2011-01-11 07:24:21 -0500688/*
689 * This is a no-op for now. We're not really interested in the reply, but
690 * rather in the fact that the server sent one and that server->lstrp
691 * gets updated.
692 *
693 * FIXME: maybe we should consider checking that the reply matches request?
694 */
695static void
696cifs_echo_callback(struct mid_q_entry *mid)
697{
698 struct TCP_Server_Info *server = mid->callback_data;
699
Christopher Oo5fb4e282015-06-25 16:10:48 -0700700 mutex_lock(&server->srv_mutex);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500701 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -0700702 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400703 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500704}
705
706int
707CIFSSMBEcho(struct TCP_Server_Info *server)
708{
709 ECHO_REQ *smb;
710 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400711 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700712 struct smb_rqst rqst = { .rq_iov = &iov,
713 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500714
Joe Perchesf96637b2013-05-04 22:12:25 -0500715 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500716
717 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
718 if (rc)
719 return rc;
720
721 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000722 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500723 smb->hdr.WordCount = 1;
724 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400725 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500726 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000727 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400728 iov.iov_base = smb;
729 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500730
Jeff Laytonfec344e2012-09-18 16:20:35 -0700731 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400732 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500733 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500734 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500735
736 cifs_small_buf_release(smb);
737
738 return rc;
739}
740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400742CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 LOGOFF_ANDX_REQ *pSMB;
745 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Joe Perchesf96637b2013-05-04 22:12:25 -0500747 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500748
749 /*
750 * BB: do we need to check validity of ses and server? They should
751 * always be valid since we have an active reference. If not, that
752 * should probably be a BUG()
753 */
754 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return -EIO;
756
Steve Frenchd7b619c2010-02-25 05:36:46 +0000757 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000758 if (ses->need_reconnect)
759 goto session_already_dead; /* no need to send SMBlogoff if uid
760 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
762 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000763 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return rc;
765 }
766
Pavel Shilovsky88257362012-05-23 14:01:59 +0400767 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700768
Jeff Layton38d77c52013-05-26 07:01:00 -0400769 if (ses->server->sign)
770 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 pSMB->hdr.Uid = ses->Suid;
773
774 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400775 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700776 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000777session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000778 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000781 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 error */
783 if (rc == -EAGAIN)
784 rc = 0;
785 return rc;
786}
787
788int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400789CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
790 const char *fileName, __u16 type,
791 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000792{
793 TRANSACTION2_SPI_REQ *pSMB = NULL;
794 TRANSACTION2_SPI_RSP *pSMBr = NULL;
795 struct unlink_psx_rq *pRqD;
796 int name_len;
797 int rc = 0;
798 int bytes_returned = 0;
799 __u16 params, param_offset, offset, byte_count;
800
Joe Perchesf96637b2013-05-04 22:12:25 -0500801 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000802PsxDelete:
803 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
804 (void **) &pSMBr);
805 if (rc)
806 return rc;
807
808 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
809 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600810 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
811 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000812 name_len++; /* trailing null */
813 name_len *= 2;
814 } else { /* BB add path length overrun check */
815 name_len = strnlen(fileName, PATH_MAX);
816 name_len++; /* trailing null */
817 strncpy(pSMB->FileName, fileName, name_len);
818 }
819
820 params = 6 + name_len;
821 pSMB->MaxParameterCount = cpu_to_le16(2);
822 pSMB->MaxDataCount = 0; /* BB double check this with jra */
823 pSMB->MaxSetupCount = 0;
824 pSMB->Reserved = 0;
825 pSMB->Flags = 0;
826 pSMB->Timeout = 0;
827 pSMB->Reserved2 = 0;
828 param_offset = offsetof(struct smb_com_transaction2_spi_req,
829 InformationLevel) - 4;
830 offset = param_offset + params;
831
832 /* Setup pointer to Request Data (inode type) */
833 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
834 pRqD->type = cpu_to_le16(type);
835 pSMB->ParameterOffset = cpu_to_le16(param_offset);
836 pSMB->DataOffset = cpu_to_le16(offset);
837 pSMB->SetupCount = 1;
838 pSMB->Reserved3 = 0;
839 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
840 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
841
842 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
843 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
844 pSMB->ParameterCount = cpu_to_le16(params);
845 pSMB->TotalParameterCount = pSMB->ParameterCount;
846 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
847 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000848 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000849 pSMB->ByteCount = cpu_to_le16(byte_count);
850 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000852 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500853 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000854 cifs_buf_release(pSMB);
855
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400856 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000857
858 if (rc == -EAGAIN)
859 goto PsxDelete;
860
861 return rc;
862}
863
864int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700865CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
866 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
868 DELETE_FILE_REQ *pSMB = NULL;
869 DELETE_FILE_RSP *pSMBr = NULL;
870 int rc = 0;
871 int bytes_returned;
872 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500873 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875DelFileRetry:
876 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
877 (void **) &pSMBr);
878 if (rc)
879 return rc;
880
881 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700882 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
883 PATH_MAX, cifs_sb->local_nls,
884 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 name_len++; /* trailing null */
886 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700887 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700888 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700890 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
892 pSMB->SearchAttributes =
893 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
894 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000895 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 pSMB->ByteCount = cpu_to_le16(name_len + 1);
897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400899 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000900 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500901 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903 cifs_buf_release(pSMB);
904 if (rc == -EAGAIN)
905 goto DelFileRetry;
906
907 return rc;
908}
909
910int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400911CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
912 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
914 DELETE_DIRECTORY_REQ *pSMB = NULL;
915 DELETE_DIRECTORY_RSP *pSMBr = NULL;
916 int rc = 0;
917 int bytes_returned;
918 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500919 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Joe Perchesf96637b2013-05-04 22:12:25 -0500921 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922RmDirRetry:
923 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
924 (void **) &pSMBr);
925 if (rc)
926 return rc;
927
928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400929 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
930 PATH_MAX, cifs_sb->local_nls,
931 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 name_len++; /* trailing null */
933 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700934 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400935 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400937 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 }
939
940 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000941 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 pSMB->ByteCount = cpu_to_le16(name_len + 1);
943 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400945 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000946 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500947 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 cifs_buf_release(pSMB);
950 if (rc == -EAGAIN)
951 goto RmDirRetry;
952 return rc;
953}
954
955int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300956CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
957 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
959 int rc = 0;
960 CREATE_DIRECTORY_REQ *pSMB = NULL;
961 CREATE_DIRECTORY_RSP *pSMBr = NULL;
962 int bytes_returned;
963 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500964 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Joe Perchesf96637b2013-05-04 22:12:25 -0500966 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967MkDirRetry:
968 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
969 (void **) &pSMBr);
970 if (rc)
971 return rc;
972
973 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600974 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300975 PATH_MAX, cifs_sb->local_nls,
976 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 name_len++; /* trailing null */
978 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700979 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 name_len = strnlen(name, PATH_MAX);
981 name_len++; /* trailing null */
982 strncpy(pSMB->DirName, name, name_len);
983 }
984
985 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000986 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 pSMB->ByteCount = cpu_to_le16(name_len + 1);
988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400990 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000991 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500992 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 cifs_buf_release(pSMB);
995 if (rc == -EAGAIN)
996 goto MkDirRetry;
997 return rc;
998}
999
Steve French2dd29d32007-04-23 22:07:35 +00001000int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001001CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1002 __u32 posix_flags, __u64 mode, __u16 *netfid,
1003 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1004 const char *name, const struct nls_table *nls_codepage,
1005 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001006{
1007 TRANSACTION2_SPI_REQ *pSMB = NULL;
1008 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1009 int name_len;
1010 int rc = 0;
1011 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001012 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001013 OPEN_PSX_REQ *pdata;
1014 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001015
Joe Perchesf96637b2013-05-04 22:12:25 -05001016 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001017PsxCreat:
1018 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1019 (void **) &pSMBr);
1020 if (rc)
1021 return rc;
1022
1023 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1024 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001025 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1026 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001027 name_len++; /* trailing null */
1028 name_len *= 2;
1029 } else { /* BB improve the check for buffer overruns BB */
1030 name_len = strnlen(name, PATH_MAX);
1031 name_len++; /* trailing null */
1032 strncpy(pSMB->FileName, name, name_len);
1033 }
1034
1035 params = 6 + name_len;
1036 count = sizeof(OPEN_PSX_REQ);
1037 pSMB->MaxParameterCount = cpu_to_le16(2);
1038 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1039 pSMB->MaxSetupCount = 0;
1040 pSMB->Reserved = 0;
1041 pSMB->Flags = 0;
1042 pSMB->Timeout = 0;
1043 pSMB->Reserved2 = 0;
1044 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001045 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001046 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001047 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001048 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001049 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001050 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001051 pdata->OpenFlags = cpu_to_le32(*pOplock);
1052 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1053 pSMB->DataOffset = cpu_to_le16(offset);
1054 pSMB->SetupCount = 1;
1055 pSMB->Reserved3 = 0;
1056 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1057 byte_count = 3 /* pad */ + params + count;
1058
1059 pSMB->DataCount = cpu_to_le16(count);
1060 pSMB->ParameterCount = cpu_to_le16(params);
1061 pSMB->TotalDataCount = pSMB->DataCount;
1062 pSMB->TotalParameterCount = pSMB->ParameterCount;
1063 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1064 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001065 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001066 pSMB->ByteCount = cpu_to_le16(byte_count);
1067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1069 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001070 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001071 goto psx_create_err;
1072 }
1073
Joe Perchesf96637b2013-05-04 22:12:25 -05001074 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001075 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1076
Jeff Layton820a8032011-05-04 08:05:26 -04001077 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001078 rc = -EIO; /* bad smb */
1079 goto psx_create_err;
1080 }
1081
1082 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001083 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001084 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001085
Steve French2dd29d32007-04-23 22:07:35 +00001086 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001087 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001088 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1089 /* Let caller know file was created so we can set the mode. */
1090 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001091 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001092 *pOplock |= CIFS_CREATE_ACTION;
1093 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001094 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1095 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001096 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001097 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001098 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001099 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001100 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001101 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001102 goto psx_create_err;
1103 }
Steve French50c2f752007-07-13 00:33:32 +00001104 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001105 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001106 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001107 }
Steve French2dd29d32007-04-23 22:07:35 +00001108
1109psx_create_err:
1110 cifs_buf_release(pSMB);
1111
Steve French65bc98b2009-07-10 15:27:25 +00001112 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001113 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001114 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001115 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001116
1117 if (rc == -EAGAIN)
1118 goto PsxCreat;
1119
Steve French50c2f752007-07-13 00:33:32 +00001120 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001121}
1122
Steve Frencha9d02ad2005-08-24 23:06:05 -07001123static __u16 convert_disposition(int disposition)
1124{
1125 __u16 ofun = 0;
1126
1127 switch (disposition) {
1128 case FILE_SUPERSEDE:
1129 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1130 break;
1131 case FILE_OPEN:
1132 ofun = SMBOPEN_OAPPEND;
1133 break;
1134 case FILE_CREATE:
1135 ofun = SMBOPEN_OCREATE;
1136 break;
1137 case FILE_OPEN_IF:
1138 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1139 break;
1140 case FILE_OVERWRITE:
1141 ofun = SMBOPEN_OTRUNC;
1142 break;
1143 case FILE_OVERWRITE_IF:
1144 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1145 break;
1146 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001147 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001148 ofun = SMBOPEN_OAPPEND; /* regular open */
1149 }
1150 return ofun;
1151}
1152
Jeff Layton35fc37d2008-05-14 10:22:03 -07001153static int
1154access_flags_to_smbopen_mode(const int access_flags)
1155{
1156 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1157
1158 if (masked_flags == GENERIC_READ)
1159 return SMBOPEN_READ;
1160 else if (masked_flags == GENERIC_WRITE)
1161 return SMBOPEN_WRITE;
1162
1163 /* just go for read/write */
1164 return SMBOPEN_READWRITE;
1165}
1166
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001168SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001170 const int access_flags, const int create_options, __u16 *netfid,
1171 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001172 const struct nls_table *nls_codepage, int remap)
1173{
1174 int rc = -EACCES;
1175 OPENX_REQ *pSMB = NULL;
1176 OPENX_RSP *pSMBr = NULL;
1177 int bytes_returned;
1178 int name_len;
1179 __u16 count;
1180
1181OldOpenRetry:
1182 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1183 (void **) &pSMBr);
1184 if (rc)
1185 return rc;
1186
1187 pSMB->AndXCommand = 0xFF; /* none */
1188
1189 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1190 count = 1; /* account for one byte pad to word boundary */
1191 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001192 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1193 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001194 name_len++; /* trailing null */
1195 name_len *= 2;
1196 } else { /* BB improve check for buffer overruns BB */
1197 count = 0; /* no pad */
1198 name_len = strnlen(fileName, PATH_MAX);
1199 name_len++; /* trailing null */
1200 strncpy(pSMB->fileName, fileName, name_len);
1201 }
1202 if (*pOplock & REQ_OPLOCK)
1203 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001204 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001205 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001206
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001208 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1210 /* set file as system file if special file such
1211 as fifo and server expecting SFU style and
1212 no Unix extensions */
1213
Steve French790fe572007-07-07 19:25:05 +00001214 if (create_options & CREATE_OPTION_SPECIAL)
1215 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001216 else /* BB FIXME BB */
1217 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001218
Jeff Layton67750fb2008-05-09 22:28:02 +00001219 if (create_options & CREATE_OPTION_READONLY)
1220 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221
1222 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001223/* pSMB->CreateOptions = cpu_to_le32(create_options &
1224 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001226
1227 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001228 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001230 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231
1232 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001234 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001235 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001237 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238 } else {
1239 /* BB verify if wct == 15 */
1240
Steve French582d21e2008-05-13 04:54:12 +00001241/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242
1243 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1244 /* Let caller know file was created so we can set the mode. */
1245 /* Do we care about the CreateAction in any other cases? */
1246 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001247/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 *pOplock |= CIFS_CREATE_ACTION; */
1249 /* BB FIXME END */
1250
Steve French790fe572007-07-07 19:25:05 +00001251 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1253 pfile_info->LastAccessTime = 0; /* BB fixme */
1254 pfile_info->LastWriteTime = 0; /* BB fixme */
1255 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001256 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001257 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001259 pfile_info->AllocationSize =
1260 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1261 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001263 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 }
1265 }
1266
1267 cifs_buf_release(pSMB);
1268 if (rc == -EAGAIN)
1269 goto OldOpenRetry;
1270 return rc;
1271}
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001274CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1275 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276{
1277 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001278 OPEN_REQ *req = NULL;
1279 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 int bytes_returned;
1281 int name_len;
1282 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001283 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1284 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001285 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001286 const struct nls_table *nls = cifs_sb->local_nls;
1287 int create_options = oparms->create_options;
1288 int desired_access = oparms->desired_access;
1289 int disposition = oparms->disposition;
1290 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291
1292openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001293 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1294 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 if (rc)
1296 return rc;
1297
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001298 /* no commands go after this */
1299 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001301 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1302 /* account for one byte pad to word boundary */
1303 count = 1;
1304 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1305 path, PATH_MAX, nls, remap);
1306 /* trailing null */
1307 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001309 req->NameLength = cpu_to_le16(name_len);
1310 } else {
1311 /* BB improve check for buffer overruns BB */
1312 /* no pad */
1313 count = 0;
1314 name_len = strnlen(path, PATH_MAX);
1315 /* trailing null */
1316 name_len++;
1317 req->NameLength = cpu_to_le16(name_len);
1318 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001320
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001321 if (*oplock & REQ_OPLOCK)
1322 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1323 else if (*oplock & REQ_BATCHOPLOCK)
1324 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1325
1326 req->DesiredAccess = cpu_to_le32(desired_access);
1327 req->AllocationSize = 0;
1328
1329 /*
1330 * Set file as system file if special file such as fifo and server
1331 * expecting SFU style and no Unix extensions.
1332 */
1333 if (create_options & CREATE_OPTION_SPECIAL)
1334 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1335 else
1336 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1337
1338 /*
1339 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1340 * sensitive checks for other servers such as Samba.
1341 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001343 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
Jeff Layton67750fb2008-05-09 22:28:02 +00001345 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001346 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001347
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001348 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1349 req->CreateDisposition = cpu_to_le32(disposition);
1350 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1351
Steve French09d1db52005-04-28 22:41:08 -07001352 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001353 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1354 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
1356 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001357 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001359 req->ByteCount = cpu_to_le16(count);
1360 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1361 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001362 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001364 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001365 cifs_buf_release(req);
1366 if (rc == -EAGAIN)
1367 goto openRetry;
1368 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001370
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001371 /* 1 byte no need to le_to_cpu */
1372 *oplock = rsp->OplockLevel;
1373 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001374 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001375
1376 /* Let caller know file was created so we can set the mode. */
1377 /* Do we care about the CreateAction in any other cases? */
1378 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1379 *oplock |= CIFS_CREATE_ACTION;
1380
1381 if (buf) {
1382 /* copy from CreationTime to Attributes */
1383 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1384 /* the file_info buf is endian converted by caller */
1385 buf->AllocationSize = rsp->AllocationSize;
1386 buf->EndOfFile = rsp->EndOfFile;
1387 buf->NumberOfLinks = cpu_to_le32(1);
1388 buf->DeletePending = 0;
1389 }
1390
1391 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 return rc;
1393}
1394
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001395/*
1396 * Discard any remaining data in the current SMB. To do this, we borrow the
1397 * current bigbuf.
1398 */
1399static int
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001400discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001401{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001402 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001403 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001404
1405 while (remaining > 0) {
1406 int length;
1407
1408 length = cifs_read_from_socket(server, server->bigbuf,
1409 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001410 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001411 if (length < 0)
1412 return length;
1413 server->total_read += length;
1414 remaining -= length;
1415 }
1416
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001417 return 0;
1418}
1419
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001420static int
1421cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1422{
1423 int length;
1424 struct cifs_readdata *rdata = mid->callback_data;
1425
1426 length = discard_remaining_data(server);
1427 dequeue_mid(mid, rdata->result);
1428 return length;
1429}
1430
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001431int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1433{
1434 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001435 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001436 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001437 char *buf = server->smallbuf;
1438 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001439
Joe Perchesf96637b2013-05-04 22:12:25 -05001440 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1441 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001442
1443 /*
1444 * read the rest of READ_RSP header (sans Data array), or whatever we
1445 * can if there's not enough data. At this point, we've read down to
1446 * the Mid.
1447 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001448 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001449 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450
Al Viroa6137302016-01-09 19:37:16 -05001451 length = cifs_read_from_socket(server,
1452 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453 if (length < 0)
1454 return length;
1455 server->total_read += length;
1456
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001457 if (server->ops->is_status_pending &&
1458 server->ops->is_status_pending(buf, server, 0)) {
1459 discard_remaining_data(server);
1460 return -1;
1461 }
1462
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001464 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001466 cifs_dbg(FYI, "%s: server returned error %d\n",
1467 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001468 return cifs_readv_discard(server, mid);
1469 }
1470
1471 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001472 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001473 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1474 __func__, server->total_read,
1475 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476 rdata->result = -EIO;
1477 return cifs_readv_discard(server, mid);
1478 }
1479
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001480 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 if (data_offset < server->total_read) {
1482 /*
1483 * win2k8 sometimes sends an offset of 0 when the read
1484 * is beyond the EOF. Treat it as if the data starts just after
1485 * the header.
1486 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001487 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1488 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 data_offset = server->total_read;
1490 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1491 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001492 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1493 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001494 rdata->result = -EIO;
1495 return cifs_readv_discard(server, mid);
1496 }
1497
Joe Perchesf96637b2013-05-04 22:12:25 -05001498 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1499 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001500
1501 len = data_offset - server->total_read;
1502 if (len > 0) {
1503 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001504 length = cifs_read_from_socket(server,
1505 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506 if (length < 0)
1507 return length;
1508 server->total_read += length;
1509 }
1510
1511 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001512 rdata->iov.iov_base = buf;
1513 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001514 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1515 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516
1517 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001518 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001519 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520 /* data_len is corrupt -- discard frame */
1521 rdata->result = -EIO;
1522 return cifs_readv_discard(server, mid);
1523 }
1524
Jeff Layton8321fec2012-09-19 06:22:32 -07001525 length = rdata->read_into_pages(server, rdata, data_len);
1526 if (length < 0)
1527 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528
Jeff Layton8321fec2012-09-19 06:22:32 -07001529 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001530
Joe Perchesf96637b2013-05-04 22:12:25 -05001531 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1532 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001533
1534 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001535 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536 return cifs_readv_discard(server, mid);
1537
1538 dequeue_mid(mid, false);
1539 return length;
1540}
1541
1542static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543cifs_readv_callback(struct mid_q_entry *mid)
1544{
1545 struct cifs_readdata *rdata = mid->callback_data;
1546 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1547 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001548 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1549 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001550 .rq_pages = rdata->pages,
1551 .rq_npages = rdata->nr_pages,
1552 .rq_pagesz = rdata->pagesz,
1553 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001554
Joe Perchesf96637b2013-05-04 22:12:25 -05001555 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1556 __func__, mid->mid, mid->mid_state, rdata->result,
1557 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001559 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560 case MID_RESPONSE_RECEIVED:
1561 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001562 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001563 int rc = 0;
1564
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001565 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001566 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001567 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001568 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1569 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001570 }
1571 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001572 task_io_account_read(rdata->got_bytes);
1573 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001574 break;
1575 case MID_REQUEST_SUBMITTED:
1576 case MID_RETRY_NEEDED:
1577 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001578 if (server->sign && rdata->got_bytes)
1579 /* reset bytes number since we can not check a sign */
1580 rdata->got_bytes = 0;
1581 /* FIXME: should this be counted toward the initiating task? */
1582 task_io_account_read(rdata->got_bytes);
1583 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001584 break;
1585 default:
1586 rdata->result = -EIO;
1587 }
1588
Jeff Laytonda472fc2012-03-23 14:40:53 -04001589 queue_work(cifsiod_wq, &rdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001590 mutex_lock(&server->srv_mutex);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001591 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001592 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001593 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001594}
1595
1596/* cifs_async_readv - send an async write, and set up mid to handle result */
1597int
1598cifs_async_readv(struct cifs_readdata *rdata)
1599{
1600 int rc;
1601 READ_REQ *smb = NULL;
1602 int wct;
1603 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001604 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001605 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001606
Joe Perchesf96637b2013-05-04 22:12:25 -05001607 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1608 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001609
1610 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1611 wct = 12;
1612 else {
1613 wct = 10; /* old style read */
1614 if ((rdata->offset >> 32) > 0) {
1615 /* can not handle this big offset for old */
1616 return -EIO;
1617 }
1618 }
1619
1620 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1621 if (rc)
1622 return rc;
1623
1624 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1625 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1626
1627 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001628 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001629 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1630 if (wct == 12)
1631 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1632 smb->Remaining = 0;
1633 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1634 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1635 if (wct == 12)
1636 smb->ByteCount = 0;
1637 else {
1638 /* old style read */
1639 struct smb_com_readx_req *smbr =
1640 (struct smb_com_readx_req *)smb;
1641 smbr->ByteCount = 0;
1642 }
1643
1644 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001645 rdata->iov.iov_base = smb;
1646 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001647
Jeff Layton6993f742012-05-16 07:13:17 -04001648 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001649 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1650 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001651
1652 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001653 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001654 else
1655 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001656
1657 cifs_small_buf_release(smb);
1658 return rc;
1659}
1660
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001662CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1663 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664{
1665 int rc = -EACCES;
1666 READ_REQ *pSMB = NULL;
1667 READ_RSP *pSMBr = NULL;
1668 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001669 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001670 int resp_buf_type = 0;
1671 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001672 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001673 __u32 pid = io_parms->pid;
1674 __u16 netfid = io_parms->netfid;
1675 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001676 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001677 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
Joe Perchesf96637b2013-05-04 22:12:25 -05001679 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001680 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001681 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001682 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001683 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001684 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001685 /* can not handle this big offset for old */
1686 return -EIO;
1687 }
1688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001691 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 if (rc)
1693 return rc;
1694
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001695 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1696 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 /* tcon and ses pointer are checked in smb_init */
1699 if (tcon->ses->server == NULL)
1700 return -ECONNABORTED;
1701
Steve Frenchec637e32005-12-12 20:53:18 -08001702 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001704 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001705 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001706 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001707
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 pSMB->Remaining = 0;
1709 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1710 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001711 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001712 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1713 else {
1714 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001715 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001716 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001717 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001718 }
Steve Frenchec637e32005-12-12 20:53:18 -08001719
1720 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001721 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001722 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1723 CIFS_LOG_ERROR, &rsp_iov);
1724 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001725 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001726 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001728 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 } else {
1730 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1731 data_length = data_length << 16;
1732 data_length += le16_to_cpu(pSMBr->DataLength);
1733 *nbytes = data_length;
1734
1735 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001736 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001738 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001739 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 rc = -EIO;
1741 *nbytes = 0;
1742 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001743 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001744 le16_to_cpu(pSMBr->DataOffset);
1745/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001746 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001747 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001748 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001749 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001750 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Steve French790fe572007-07-07 19:25:05 +00001754 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001755 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001756 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001757 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001758 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001759 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001760 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001761 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001762 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001763 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001764
1765 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 since file handle passed in no longer valid */
1767 return rc;
1768}
1769
Steve Frenchec637e32005-12-12 20:53:18 -08001770
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001772CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001773 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774{
1775 int rc = -EACCES;
1776 WRITE_REQ *pSMB = NULL;
1777 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001778 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 __u32 bytes_sent;
1780 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001781 __u32 pid = io_parms->pid;
1782 __u16 netfid = io_parms->netfid;
1783 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001784 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001785 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
Steve Frencha24e2d72010-04-03 17:20:21 +00001787 *nbytes = 0;
1788
Joe Perchesf96637b2013-05-04 22:12:25 -05001789 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001790 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001791 return -ECONNABORTED;
1792
Steve French790fe572007-07-07 19:25:05 +00001793 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001794 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001795 else {
Steve French1c955182005-08-30 20:58:07 -07001796 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001797 if ((offset >> 32) > 0) {
1798 /* can not handle big offset for old srv */
1799 return -EIO;
1800 }
1801 }
Steve French1c955182005-08-30 20:58:07 -07001802
1803 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 (void **) &pSMBr);
1805 if (rc)
1806 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001807
1808 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1809 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 /* tcon and ses pointer are checked in smb_init */
1812 if (tcon->ses->server == NULL)
1813 return -ECONNABORTED;
1814
1815 pSMB->AndXCommand = 0xFF; /* none */
1816 pSMB->Fid = netfid;
1817 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001818 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001819 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 pSMB->Reserved = 0xFFFFFFFF;
1822 pSMB->WriteMode = 0;
1823 pSMB->Remaining = 0;
1824
Steve French50c2f752007-07-13 00:33:32 +00001825 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 can send more if LARGE_WRITE_X capability returned by the server and if
1827 our buffer is big enough or if we convert to iovecs on socket writes
1828 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001829 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1831 } else {
1832 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1833 & ~0xFF;
1834 }
1835
1836 if (bytes_sent > count)
1837 bytes_sent = count;
1838 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001839 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001840 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001841 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001842 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 /* No buffer */
1844 cifs_buf_release(pSMB);
1845 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001846 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001847 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001848 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001849 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001850 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1853 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001854 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001855
Steve French790fe572007-07-07 19:25:05 +00001856 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001857 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001858 else { /* old style write has byte count 4 bytes earlier
1859 so 4 bytes pad */
1860 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001861 (struct smb_com_writex_req *)pSMB;
1862 pSMBW->ByteCount = cpu_to_le16(byte_count);
1863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001866 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001867 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001869 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 } else {
1871 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1872 *nbytes = (*nbytes) << 16;
1873 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301874
1875 /*
1876 * Mask off high 16 bits when bytes written as returned by the
1877 * server is greater than bytes requested by the client. Some
1878 * OS/2 servers are known to set incorrect CountHigh values.
1879 */
1880 if (*nbytes > count)
1881 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 }
1883
1884 cifs_buf_release(pSMB);
1885
Steve French50c2f752007-07-13 00:33:32 +00001886 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 since file handle passed in no longer valid */
1888
1889 return rc;
1890}
1891
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001892void
1893cifs_writedata_release(struct kref *refcount)
1894{
1895 struct cifs_writedata *wdata = container_of(refcount,
1896 struct cifs_writedata, refcount);
1897
1898 if (wdata->cfile)
1899 cifsFileInfo_put(wdata->cfile);
1900
1901 kfree(wdata);
1902}
1903
1904/*
1905 * Write failed with a retryable error. Resend the write request. It's also
1906 * possible that the page was redirtied so re-clean the page.
1907 */
1908static void
1909cifs_writev_requeue(struct cifs_writedata *wdata)
1910{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001911 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001912 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001913 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001914 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001915
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001916 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1917 i = 0;
1918 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001919 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001920 struct cifs_writedata *wdata2;
1921 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001922
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001923 wsize = server->ops->wp_retry_size(inode);
1924 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001925 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001926 if (!nr_pages) {
1927 rc = -ENOTSUPP;
1928 break;
1929 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001930 cur_len = nr_pages * PAGE_SIZE;
1931 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001932 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001933 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001934 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001935 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001936 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001937
1938 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1939 if (!wdata2) {
1940 rc = -ENOMEM;
1941 break;
1942 }
1943
1944 for (j = 0; j < nr_pages; j++) {
1945 wdata2->pages[j] = wdata->pages[i + j];
1946 lock_page(wdata2->pages[j]);
1947 clear_page_dirty_for_io(wdata2->pages[j]);
1948 }
1949
1950 wdata2->sync_mode = wdata->sync_mode;
1951 wdata2->nr_pages = nr_pages;
1952 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001953 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001954 wdata2->tailsz = tailsz;
1955 wdata2->bytes = cur_len;
1956
1957 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1958 if (!wdata2->cfile) {
1959 cifs_dbg(VFS, "No writable handles for inode\n");
1960 rc = -EBADF;
1961 break;
1962 }
1963 wdata2->pid = wdata2->cfile->pid;
1964 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1965
1966 for (j = 0; j < nr_pages; j++) {
1967 unlock_page(wdata2->pages[j]);
1968 if (rc != 0 && rc != -EAGAIN) {
1969 SetPageError(wdata2->pages[j]);
1970 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001971 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001972 }
1973 }
1974
1975 if (rc) {
1976 kref_put(&wdata2->refcount, cifs_writedata_release);
1977 if (rc == -EAGAIN)
1978 continue;
1979 break;
1980 }
1981
1982 rest_len -= cur_len;
1983 i += nr_pages;
1984 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001985
1986 mapping_set_error(inode->i_mapping, rc);
1987 kref_put(&wdata->refcount, cifs_writedata_release);
1988}
1989
Jeff Laytonc2e87642012-03-23 14:40:55 -04001990void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001991cifs_writev_complete(struct work_struct *work)
1992{
1993 struct cifs_writedata *wdata = container_of(work,
1994 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00001995 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001996 int i = 0;
1997
1998 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001999 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002000 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002001 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002002 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2003 wdata->bytes);
2004 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2005 return cifs_writev_requeue(wdata);
2006
2007 for (i = 0; i < wdata->nr_pages; i++) {
2008 struct page *page = wdata->pages[i];
2009 if (wdata->result == -EAGAIN)
2010 __set_page_dirty_nobuffers(page);
2011 else if (wdata->result < 0)
2012 SetPageError(page);
2013 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002014 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002015 }
2016 if (wdata->result != -EAGAIN)
2017 mapping_set_error(inode->i_mapping, wdata->result);
2018 kref_put(&wdata->refcount, cifs_writedata_release);
2019}
2020
2021struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002022cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002023{
2024 struct cifs_writedata *wdata;
2025
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002026 /* writedata + number of page pointers */
2027 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002028 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002029 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002030 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002031 INIT_LIST_HEAD(&wdata->list);
2032 init_completion(&wdata->done);
2033 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002034 }
2035 return wdata;
2036}
2037
2038/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002039 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040 * workqueue completion task.
2041 */
2042static void
2043cifs_writev_callback(struct mid_q_entry *mid)
2044{
2045 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002046 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002047 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002048 unsigned int written;
2049 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2050
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002051 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052 case MID_RESPONSE_RECEIVED:
2053 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2054 if (wdata->result != 0)
2055 break;
2056
2057 written = le16_to_cpu(smb->CountHigh);
2058 written <<= 16;
2059 written += le16_to_cpu(smb->Count);
2060 /*
2061 * Mask off high 16 bits when bytes written as returned
2062 * by the server is greater than bytes requested by the
2063 * client. OS/2 servers are known to set incorrect
2064 * CountHigh values.
2065 */
2066 if (written > wdata->bytes)
2067 written &= 0xFFFF;
2068
2069 if (written < wdata->bytes)
2070 wdata->result = -ENOSPC;
2071 else
2072 wdata->bytes = written;
2073 break;
2074 case MID_REQUEST_SUBMITTED:
2075 case MID_RETRY_NEEDED:
2076 wdata->result = -EAGAIN;
2077 break;
2078 default:
2079 wdata->result = -EIO;
2080 break;
2081 }
2082
Jeff Laytonda472fc2012-03-23 14:40:53 -04002083 queue_work(cifsiod_wq, &wdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002084 mutex_lock(&server->srv_mutex);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002085 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002086 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002087 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002088}
2089
2090/* cifs_async_writev - send an async write, and set up mid to handle result */
2091int
Steve French4a5c80d2014-02-07 20:45:12 -06002092cifs_async_writev(struct cifs_writedata *wdata,
2093 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002095 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002096 WRITE_REQ *smb = NULL;
2097 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002098 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002099 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002100 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101
2102 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2103 wct = 14;
2104 } else {
2105 wct = 12;
2106 if (wdata->offset >> 32 > 0) {
2107 /* can not handle big offset for old srv */
2108 return -EIO;
2109 }
2110 }
2111
2112 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2113 if (rc)
2114 goto async_writev_out;
2115
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002116 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2117 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002118
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002119 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002120 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002121 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2122 if (wct == 14)
2123 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2124 smb->Reserved = 0xFFFFFFFF;
2125 smb->WriteMode = 0;
2126 smb->Remaining = 0;
2127
2128 smb->DataOffset =
2129 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2130
2131 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002132 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2133 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002134
Jeff Laytoneddb0792012-09-18 16:20:35 -07002135 rqst.rq_iov = &iov;
2136 rqst.rq_nvec = 1;
2137 rqst.rq_pages = wdata->pages;
2138 rqst.rq_npages = wdata->nr_pages;
2139 rqst.rq_pagesz = wdata->pagesz;
2140 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002141
Joe Perchesf96637b2013-05-04 22:12:25 -05002142 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2143 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002144
2145 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2146 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2147
2148 if (wct == 14) {
2149 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2150 put_bcc(wdata->bytes + 1, &smb->hdr);
2151 } else {
2152 /* wct == 12 */
2153 struct smb_com_writex_req *smbw =
2154 (struct smb_com_writex_req *)smb;
2155 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2156 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002157 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002158 }
2159
2160 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002161 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2162 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002163
2164 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002165 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002166 else
Steve French4a5c80d2014-02-07 20:45:12 -06002167 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002168
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169async_writev_out:
2170 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002171 return rc;
2172}
2173
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002174int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002175CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002176 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177{
2178 int rc = -EACCES;
2179 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002180 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002181 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002182 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002183 __u32 pid = io_parms->pid;
2184 __u16 netfid = io_parms->netfid;
2185 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002186 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002187 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002188 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002190 *nbytes = 0;
2191
Joe Perchesf96637b2013-05-04 22:12:25 -05002192 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002193
Steve French4c3130e2008-12-09 00:28:16 +00002194 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002195 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002196 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002197 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002198 if ((offset >> 32) > 0) {
2199 /* can not handle big offset for old srv */
2200 return -EIO;
2201 }
2202 }
Steve French8cc64c62005-10-03 13:49:43 -07002203 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 if (rc)
2205 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002206
2207 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2208 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2209
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 /* tcon and ses pointer are checked in smb_init */
2211 if (tcon->ses->server == NULL)
2212 return -ECONNABORTED;
2213
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002214 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 pSMB->Fid = netfid;
2216 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002217 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002218 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 pSMB->Reserved = 0xFFFFFFFF;
2220 pSMB->WriteMode = 0;
2221 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002224 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Steve French3e844692005-10-03 13:37:24 -07002226 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2227 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002228 /* header + 1 byte pad */
2229 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002230 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002231 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002232 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002233 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002234 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002235 pSMB->ByteCount = cpu_to_le16(count + 1);
2236 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002237 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002238 (struct smb_com_writex_req *)pSMB;
2239 pSMBW->ByteCount = cpu_to_le16(count + 5);
2240 }
Steve French3e844692005-10-03 13:37:24 -07002241 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002242 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002243 iov[0].iov_len = smb_hdr_len + 4;
2244 else /* wct == 12 pad bigger by four bytes */
2245 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002246
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002247 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2248 &rsp_iov);
2249 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002250 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002252 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002253 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002254 /* presumably this can not happen, but best to be safe */
2255 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002256 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002257 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002258 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2259 *nbytes = (*nbytes) << 16;
2260 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302261
2262 /*
2263 * Mask off high 16 bits when bytes written as returned by the
2264 * server is greater than bytes requested by the client. OS/2
2265 * servers are known to set incorrect CountHigh values.
2266 */
2267 if (*nbytes > count)
2268 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002271 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
Steve French50c2f752007-07-13 00:33:32 +00002273 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 since file handle passed in no longer valid */
2275
2276 return rc;
2277}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002278
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002279int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2280 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002281 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2282{
2283 int rc = 0;
2284 LOCK_REQ *pSMB = NULL;
2285 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002286 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002287 int resp_buf_type;
2288 __u16 count;
2289
Joe Perchesf96637b2013-05-04 22:12:25 -05002290 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2291 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002292
2293 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2294 if (rc)
2295 return rc;
2296
2297 pSMB->Timeout = 0;
2298 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2299 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2300 pSMB->LockType = lock_type;
2301 pSMB->AndXCommand = 0xFF; /* none */
2302 pSMB->Fid = netfid; /* netfid stays le */
2303
2304 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2305 inc_rfc1001_len(pSMB, count);
2306 pSMB->ByteCount = cpu_to_le16(count);
2307
2308 iov[0].iov_base = (char *)pSMB;
2309 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2310 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2311 iov[1].iov_base = (char *)buf;
2312 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2313
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002314 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002315 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2316 &rsp_iov);
2317 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002318 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002319 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002320
2321 return rc;
2322}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002323
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002325CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002326 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002328 const __u32 numLock, const __u8 lockType,
2329 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330{
2331 int rc = 0;
2332 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002333/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002335 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 __u16 count;
2337
Joe Perchesf96637b2013-05-04 22:12:25 -05002338 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2339 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002340 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2341
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 if (rc)
2343 return rc;
2344
Steve French790fe572007-07-07 19:25:05 +00002345 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002346 /* no response expected */
2347 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002349 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002350 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2352 } else {
2353 pSMB->Timeout = 0;
2354 }
2355
2356 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2357 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2358 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002359 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 pSMB->AndXCommand = 0xFF; /* none */
2361 pSMB->Fid = smb_file_id; /* netfid stays le */
2362
Steve French790fe572007-07-07 19:25:05 +00002363 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002364 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 /* BB where to store pid high? */
2366 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2367 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2368 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2369 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2370 count = sizeof(LOCKING_ANDX_RANGE);
2371 } else {
2372 /* oplock break */
2373 count = 0;
2374 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002375 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 pSMB->ByteCount = cpu_to_le16(count);
2377
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002378 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002379 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002380 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002381 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002382 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002383 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002384 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002385 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002386 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Steve French50c2f752007-07-13 00:33:32 +00002388 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 since file handle passed in no longer valid */
2390 return rc;
2391}
2392
2393int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002394CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002395 const __u16 smb_file_id, const __u32 netpid,
2396 const loff_t start_offset, const __u64 len,
2397 struct file_lock *pLockData, const __u16 lock_type,
2398 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002399{
2400 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2401 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002402 struct cifs_posix_lock *parm_data;
2403 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002404 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002405 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002406 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002407 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002408 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002409 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002410
Joe Perchesf96637b2013-05-04 22:12:25 -05002411 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002412
Steve French08547b02006-02-28 22:39:25 +00002413 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2414
2415 if (rc)
2416 return rc;
2417
2418 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2419
Steve French50c2f752007-07-13 00:33:32 +00002420 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002421 pSMB->MaxSetupCount = 0;
2422 pSMB->Reserved = 0;
2423 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002424 pSMB->Reserved2 = 0;
2425 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2426 offset = param_offset + params;
2427
Steve French08547b02006-02-28 22:39:25 +00002428 count = sizeof(struct cifs_posix_lock);
2429 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002430 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002431 pSMB->SetupCount = 1;
2432 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002433 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002434 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2435 else
2436 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2437 byte_count = 3 /* pad */ + params + count;
2438 pSMB->DataCount = cpu_to_le16(count);
2439 pSMB->ParameterCount = cpu_to_le16(params);
2440 pSMB->TotalDataCount = pSMB->DataCount;
2441 pSMB->TotalParameterCount = pSMB->ParameterCount;
2442 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002443 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002444 (((char *) &pSMB->hdr.Protocol) + offset);
2445
2446 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002447 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002448 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002449 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002450 pSMB->Timeout = cpu_to_le32(-1);
2451 } else
2452 pSMB->Timeout = 0;
2453
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002454 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002455 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002456 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002457
2458 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002459 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002460 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2461 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002462 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002463 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002464 if (waitFlag) {
2465 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2466 (struct smb_hdr *) pSMBr, &bytes_returned);
2467 } else {
Steve French133672e2007-11-13 22:41:37 +00002468 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002469 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002470 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002471 &resp_buf_type, timeout, &rsp_iov);
2472 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002473 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002474 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002475
Steve French08547b02006-02-28 22:39:25 +00002476 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002477 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002478 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002479 /* lock structure can be returned on get */
2480 __u16 data_offset;
2481 __u16 data_count;
2482 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002483
Jeff Layton820a8032011-05-04 08:05:26 -04002484 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002485 rc = -EIO; /* bad smb */
2486 goto plk_err_exit;
2487 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002488 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2489 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002490 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002491 rc = -EIO;
2492 goto plk_err_exit;
2493 }
2494 parm_data = (struct cifs_posix_lock *)
2495 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002496 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002497 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002498 else {
2499 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002500 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002501 pLockData->fl_type = F_RDLCK;
2502 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002503 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002504 pLockData->fl_type = F_WRLCK;
2505
Steve French5443d132011-03-13 05:08:25 +00002506 pLockData->fl_start = le64_to_cpu(parm_data->start);
2507 pLockData->fl_end = pLockData->fl_start +
2508 le64_to_cpu(parm_data->length) - 1;
2509 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002510 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002511 }
Steve French50c2f752007-07-13 00:33:32 +00002512
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002513plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002514 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002515
Steve French08547b02006-02-28 22:39:25 +00002516 /* Note: On -EAGAIN error only caller can retry on handle based calls
2517 since file handle passed in no longer valid */
2518
2519 return rc;
2520}
2521
2522
2523int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002524CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525{
2526 int rc = 0;
2527 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002528 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530/* do not retry on dead session on close */
2531 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002532 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 return 0;
2534 if (rc)
2535 return rc;
2536
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002538 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002540 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002541 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002542 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002544 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002546 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 }
2548 }
2549
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002551 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 rc = 0;
2553
2554 return rc;
2555}
2556
2557int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002558CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002559{
2560 int rc = 0;
2561 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002562 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002563
2564 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2565 if (rc)
2566 return rc;
2567
2568 pSMB->FileID = (__u16) smb_file_id;
2569 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002570 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002571 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002572 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002573 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002574 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002575
2576 return rc;
2577}
2578
2579int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002580CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002581 const char *from_name, const char *to_name,
2582 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583{
2584 int rc = 0;
2585 RENAME_REQ *pSMB = NULL;
2586 RENAME_RSP *pSMBr = NULL;
2587 int bytes_returned;
2588 int name_len, name_len2;
2589 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002590 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
Joe Perchesf96637b2013-05-04 22:12:25 -05002592 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593renameRetry:
2594 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2595 (void **) &pSMBr);
2596 if (rc)
2597 return rc;
2598
2599 pSMB->BufferFormat = 0x04;
2600 pSMB->SearchAttributes =
2601 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2602 ATTR_DIRECTORY);
2603
2604 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002605 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2606 from_name, PATH_MAX,
2607 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 name_len++; /* trailing null */
2609 name_len *= 2;
2610 pSMB->OldFileName[name_len] = 0x04; /* pad */
2611 /* protocol requires ASCII signature byte on Unicode string */
2612 pSMB->OldFileName[name_len + 1] = 0x00;
2613 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002614 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002615 to_name, PATH_MAX, cifs_sb->local_nls,
2616 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2618 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002619 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002620 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002622 strncpy(pSMB->OldFileName, from_name, name_len);
2623 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 name_len2++; /* trailing null */
2625 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002626 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 name_len2++; /* trailing null */
2628 name_len2++; /* signature byte */
2629 }
2630
2631 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002632 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 pSMB->ByteCount = cpu_to_le16(count);
2634
2635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002637 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002638 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002639 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 cifs_buf_release(pSMB);
2642
2643 if (rc == -EAGAIN)
2644 goto renameRetry;
2645
2646 return rc;
2647}
2648
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002649int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002650 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002651 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652{
2653 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2654 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002655 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 char *data_offset;
2657 char dummy_string[30];
2658 int rc = 0;
2659 int bytes_returned = 0;
2660 int len_of_str;
2661 __u16 params, param_offset, offset, count, byte_count;
2662
Joe Perchesf96637b2013-05-04 22:12:25 -05002663 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2665 (void **) &pSMBr);
2666 if (rc)
2667 return rc;
2668
2669 params = 6;
2670 pSMB->MaxSetupCount = 0;
2671 pSMB->Reserved = 0;
2672 pSMB->Flags = 0;
2673 pSMB->Timeout = 0;
2674 pSMB->Reserved2 = 0;
2675 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2676 offset = param_offset + params;
2677
2678 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2679 rename_info = (struct set_file_rename *) data_offset;
2680 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002681 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 pSMB->SetupCount = 1;
2683 pSMB->Reserved3 = 0;
2684 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2685 byte_count = 3 /* pad */ + params;
2686 pSMB->ParameterCount = cpu_to_le16(params);
2687 pSMB->TotalParameterCount = pSMB->ParameterCount;
2688 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2689 pSMB->DataOffset = cpu_to_le16(offset);
2690 /* construct random name ".cifs_tmp<inodenum><mid>" */
2691 rename_info->overwrite = cpu_to_le32(1);
2692 rename_info->root_fid = 0;
2693 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002694 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002695 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002696 len_of_str =
2697 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002698 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002700 len_of_str =
2701 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002702 target_name, PATH_MAX, nls_codepage,
2703 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 }
2705 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002706 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 byte_count += count;
2708 pSMB->DataCount = cpu_to_le16(count);
2709 pSMB->TotalDataCount = pSMB->DataCount;
2710 pSMB->Fid = netfid;
2711 pSMB->InformationLevel =
2712 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2713 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002714 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 pSMB->ByteCount = cpu_to_le16(byte_count);
2716 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002717 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002718 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002719 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002720 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2721 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002722
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 cifs_buf_release(pSMB);
2724
2725 /* Note: On -EAGAIN error only caller can retry on handle based calls
2726 since file handle passed in no longer valid */
2727
2728 return rc;
2729}
2730
2731int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002732CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2733 const char *fromName, const __u16 target_tid, const char *toName,
2734 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735{
2736 int rc = 0;
2737 COPY_REQ *pSMB = NULL;
2738 COPY_RSP *pSMBr = NULL;
2739 int bytes_returned;
2740 int name_len, name_len2;
2741 __u16 count;
2742
Joe Perchesf96637b2013-05-04 22:12:25 -05002743 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744copyRetry:
2745 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2746 (void **) &pSMBr);
2747 if (rc)
2748 return rc;
2749
2750 pSMB->BufferFormat = 0x04;
2751 pSMB->Tid2 = target_tid;
2752
2753 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2754
2755 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002756 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2757 fromName, PATH_MAX, nls_codepage,
2758 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 name_len++; /* trailing null */
2760 name_len *= 2;
2761 pSMB->OldFileName[name_len] = 0x04; /* pad */
2762 /* protocol requires ASCII signature byte on Unicode string */
2763 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002764 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002765 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2766 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2768 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002769 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 name_len = strnlen(fromName, PATH_MAX);
2771 name_len++; /* trailing null */
2772 strncpy(pSMB->OldFileName, fromName, name_len);
2773 name_len2 = strnlen(toName, PATH_MAX);
2774 name_len2++; /* trailing null */
2775 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2776 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2777 name_len2++; /* trailing null */
2778 name_len2++; /* signature byte */
2779 }
2780
2781 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002782 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 pSMB->ByteCount = cpu_to_le16(count);
2784
2785 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2786 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2787 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002788 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2789 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 }
Steve French0d817bc2008-05-22 02:02:03 +00002791 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 if (rc == -EAGAIN)
2794 goto copyRetry;
2795
2796 return rc;
2797}
2798
2799int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002800CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002802 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803{
2804 TRANSACTION2_SPI_REQ *pSMB = NULL;
2805 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2806 char *data_offset;
2807 int name_len;
2808 int name_len_target;
2809 int rc = 0;
2810 int bytes_returned = 0;
2811 __u16 params, param_offset, offset, byte_count;
2812
Joe Perchesf96637b2013-05-04 22:12:25 -05002813 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814createSymLinkRetry:
2815 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2816 (void **) &pSMBr);
2817 if (rc)
2818 return rc;
2819
2820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2821 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002822 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2823 /* find define for this maxpathcomponent */
2824 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 name_len++; /* trailing null */
2826 name_len *= 2;
2827
Steve French50c2f752007-07-13 00:33:32 +00002828 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 name_len = strnlen(fromName, PATH_MAX);
2830 name_len++; /* trailing null */
2831 strncpy(pSMB->FileName, fromName, name_len);
2832 }
2833 params = 6 + name_len;
2834 pSMB->MaxSetupCount = 0;
2835 pSMB->Reserved = 0;
2836 pSMB->Flags = 0;
2837 pSMB->Timeout = 0;
2838 pSMB->Reserved2 = 0;
2839 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002840 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 offset = param_offset + params;
2842
2843 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2844 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2845 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002846 cifsConvertToUTF16((__le16 *) data_offset, toName,
2847 /* find define for this maxpathcomponent */
2848 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 name_len_target++; /* trailing null */
2850 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002851 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 name_len_target = strnlen(toName, PATH_MAX);
2853 name_len_target++; /* trailing null */
2854 strncpy(data_offset, toName, name_len_target);
2855 }
2856
2857 pSMB->MaxParameterCount = cpu_to_le16(2);
2858 /* BB find exact max on data count below from sess */
2859 pSMB->MaxDataCount = cpu_to_le16(1000);
2860 pSMB->SetupCount = 1;
2861 pSMB->Reserved3 = 0;
2862 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2863 byte_count = 3 /* pad */ + params + name_len_target;
2864 pSMB->DataCount = cpu_to_le16(name_len_target);
2865 pSMB->ParameterCount = cpu_to_le16(params);
2866 pSMB->TotalDataCount = pSMB->DataCount;
2867 pSMB->TotalParameterCount = pSMB->ParameterCount;
2868 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2869 pSMB->DataOffset = cpu_to_le16(offset);
2870 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2871 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002872 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 pSMB->ByteCount = cpu_to_le16(byte_count);
2874 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2875 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002876 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002877 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002878 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2879 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
Steve French0d817bc2008-05-22 02:02:03 +00002881 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
2883 if (rc == -EAGAIN)
2884 goto createSymLinkRetry;
2885
2886 return rc;
2887}
2888
2889int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002890CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002892 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893{
2894 TRANSACTION2_SPI_REQ *pSMB = NULL;
2895 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2896 char *data_offset;
2897 int name_len;
2898 int name_len_target;
2899 int rc = 0;
2900 int bytes_returned = 0;
2901 __u16 params, param_offset, offset, byte_count;
2902
Joe Perchesf96637b2013-05-04 22:12:25 -05002903 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904createHardLinkRetry:
2905 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2906 (void **) &pSMBr);
2907 if (rc)
2908 return rc;
2909
2910 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002911 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2912 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 name_len++; /* trailing null */
2914 name_len *= 2;
2915
Steve French50c2f752007-07-13 00:33:32 +00002916 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 name_len = strnlen(toName, PATH_MAX);
2918 name_len++; /* trailing null */
2919 strncpy(pSMB->FileName, toName, name_len);
2920 }
2921 params = 6 + name_len;
2922 pSMB->MaxSetupCount = 0;
2923 pSMB->Reserved = 0;
2924 pSMB->Flags = 0;
2925 pSMB->Timeout = 0;
2926 pSMB->Reserved2 = 0;
2927 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002928 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 offset = param_offset + params;
2930
2931 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2933 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002934 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2935 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 name_len_target++; /* trailing null */
2937 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002938 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 name_len_target = strnlen(fromName, PATH_MAX);
2940 name_len_target++; /* trailing null */
2941 strncpy(data_offset, fromName, name_len_target);
2942 }
2943
2944 pSMB->MaxParameterCount = cpu_to_le16(2);
2945 /* BB find exact max on data count below from sess*/
2946 pSMB->MaxDataCount = cpu_to_le16(1000);
2947 pSMB->SetupCount = 1;
2948 pSMB->Reserved3 = 0;
2949 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2950 byte_count = 3 /* pad */ + params + name_len_target;
2951 pSMB->ParameterCount = cpu_to_le16(params);
2952 pSMB->TotalParameterCount = pSMB->ParameterCount;
2953 pSMB->DataCount = cpu_to_le16(name_len_target);
2954 pSMB->TotalDataCount = pSMB->DataCount;
2955 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2956 pSMB->DataOffset = cpu_to_le16(offset);
2957 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2958 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002959 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 pSMB->ByteCount = cpu_to_le16(byte_count);
2961 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2962 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002963 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002964 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002965 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2966 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
2968 cifs_buf_release(pSMB);
2969 if (rc == -EAGAIN)
2970 goto createHardLinkRetry;
2971
2972 return rc;
2973}
2974
2975int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002976CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002977 const char *from_name, const char *to_name,
2978 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979{
2980 int rc = 0;
2981 NT_RENAME_REQ *pSMB = NULL;
2982 RENAME_RSP *pSMBr = NULL;
2983 int bytes_returned;
2984 int name_len, name_len2;
2985 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002986 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
Joe Perchesf96637b2013-05-04 22:12:25 -05002988 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989winCreateHardLinkRetry:
2990
2991 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2992 (void **) &pSMBr);
2993 if (rc)
2994 return rc;
2995
2996 pSMB->SearchAttributes =
2997 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2998 ATTR_DIRECTORY);
2999 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3000 pSMB->ClusterCount = 0;
3001
3002 pSMB->BufferFormat = 0x04;
3003
3004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3005 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003006 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3007 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 name_len++; /* trailing null */
3009 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003010
3011 /* protocol specifies ASCII buffer format (0x04) for unicode */
3012 pSMB->OldFileName[name_len] = 0x04;
3013 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003015 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003016 to_name, PATH_MAX, cifs_sb->local_nls,
3017 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3019 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003020 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003021 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003023 strncpy(pSMB->OldFileName, from_name, name_len);
3024 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 name_len2++; /* trailing null */
3026 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003027 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 name_len2++; /* trailing null */
3029 name_len2++; /* signature byte */
3030 }
3031
3032 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003033 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 pSMB->ByteCount = cpu_to_le16(count);
3035
3036 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003038 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003039 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003040 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003041
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 cifs_buf_release(pSMB);
3043 if (rc == -EAGAIN)
3044 goto winCreateHardLinkRetry;
3045
3046 return rc;
3047}
3048
3049int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003050CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003051 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003052 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053{
3054/* SMB_QUERY_FILE_UNIX_LINK */
3055 TRANSACTION2_QPI_REQ *pSMB = NULL;
3056 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3057 int rc = 0;
3058 int bytes_returned;
3059 int name_len;
3060 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003061 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
Joe Perchesf96637b2013-05-04 22:12:25 -05003063 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
3065querySymLinkRetry:
3066 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3067 (void **) &pSMBr);
3068 if (rc)
3069 return rc;
3070
3071 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3072 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003073 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3074 searchName, PATH_MAX, nls_codepage,
3075 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 name_len++; /* trailing null */
3077 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003078 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 name_len = strnlen(searchName, PATH_MAX);
3080 name_len++; /* trailing null */
3081 strncpy(pSMB->FileName, searchName, name_len);
3082 }
3083
3084 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3085 pSMB->TotalDataCount = 0;
3086 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003087 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 pSMB->MaxSetupCount = 0;
3089 pSMB->Reserved = 0;
3090 pSMB->Flags = 0;
3091 pSMB->Timeout = 0;
3092 pSMB->Reserved2 = 0;
3093 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003094 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 pSMB->DataCount = 0;
3096 pSMB->DataOffset = 0;
3097 pSMB->SetupCount = 1;
3098 pSMB->Reserved3 = 0;
3099 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3100 byte_count = params + 1 /* pad */ ;
3101 pSMB->TotalParameterCount = cpu_to_le16(params);
3102 pSMB->ParameterCount = pSMB->TotalParameterCount;
3103 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3104 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003105 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 pSMB->ByteCount = cpu_to_le16(byte_count);
3107
3108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3109 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3110 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003111 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 } else {
3113 /* decode response */
3114
3115 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003117 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003118 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003120 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003121 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
Jeff Layton460b9692009-04-30 07:17:56 -04003123 data_start = ((char *) &pSMBr->hdr.Protocol) +
3124 le16_to_cpu(pSMBr->t2.DataOffset);
3125
Steve French0e0d2cf2009-05-01 05:27:32 +00003126 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3127 is_unicode = true;
3128 else
3129 is_unicode = false;
3130
Steve French737b7582005-04-28 22:41:06 -07003131 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003132 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3133 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003134 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003135 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 }
3137 }
3138 cifs_buf_release(pSMB);
3139 if (rc == -EAGAIN)
3140 goto querySymLinkRetry;
3141 return rc;
3142}
3143
Steve Frenchc52a95542011-02-24 06:16:22 +00003144/*
3145 * Recent Windows versions now create symlinks more frequently
3146 * and they use the "reparse point" mechanism below. We can of course
3147 * do symlinks nicely to Samba and other servers which support the
3148 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3149 * "MF" symlinks optionally, but for recent Windows we really need to
3150 * reenable the code below and fix the cifs_symlink callers to handle this.
3151 * In the interim this code has been moved to its own config option so
3152 * it is not compiled in by default until callers fixed up and more tested.
3153 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003155CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3156 __u16 fid, char **symlinkinfo,
3157 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158{
3159 int rc = 0;
3160 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003161 struct smb_com_transaction_ioctl_req *pSMB;
3162 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003163 bool is_unicode;
3164 unsigned int sub_len;
3165 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003166 struct reparse_symlink_data *reparse_buf;
3167 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003168 __u32 data_offset, data_count;
3169 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003171 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3173 (void **) &pSMBr);
3174 if (rc)
3175 return rc;
3176
3177 pSMB->TotalParameterCount = 0 ;
3178 pSMB->TotalDataCount = 0;
3179 pSMB->MaxParameterCount = cpu_to_le32(2);
3180 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003181 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 pSMB->MaxSetupCount = 4;
3183 pSMB->Reserved = 0;
3184 pSMB->ParameterOffset = 0;
3185 pSMB->DataCount = 0;
3186 pSMB->DataOffset = 0;
3187 pSMB->SetupCount = 4;
3188 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3189 pSMB->ParameterCount = pSMB->TotalParameterCount;
3190 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3191 pSMB->IsFsctl = 1; /* FSCTL */
3192 pSMB->IsRootFlag = 0;
3193 pSMB->Fid = fid; /* file handle always le */
3194 pSMB->ByteCount = 0;
3195
3196 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3198 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003199 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003200 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
Steve French989c7e52009-05-02 05:32:20 +00003202
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003203 data_offset = le32_to_cpu(pSMBr->DataOffset);
3204 data_count = le32_to_cpu(pSMBr->DataCount);
3205 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3206 /* BB also check enough total bytes returned */
3207 rc = -EIO; /* bad smb */
3208 goto qreparse_out;
3209 }
3210 if (!data_count || (data_count > 2048)) {
3211 rc = -EIO;
3212 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3213 goto qreparse_out;
3214 }
3215 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003216 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003217 ((char *)&pSMBr->hdr.Protocol + data_offset);
3218 if ((char *)reparse_buf >= end_of_smb) {
3219 rc = -EIO;
3220 goto qreparse_out;
3221 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003222 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3223 cifs_dbg(FYI, "NFS style reparse tag\n");
3224 posix_buf = (struct reparse_posix_data *)reparse_buf;
3225
3226 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3227 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3228 le64_to_cpu(posix_buf->InodeType));
3229 rc = -EOPNOTSUPP;
3230 goto qreparse_out;
3231 }
3232 is_unicode = true;
3233 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3234 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3235 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3236 rc = -EIO;
3237 goto qreparse_out;
3238 }
3239 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3240 sub_len, is_unicode, nls_codepage);
3241 goto qreparse_out;
3242 } else if (reparse_buf->ReparseTag !=
3243 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3244 rc = -EOPNOTSUPP;
3245 goto qreparse_out;
3246 }
3247
3248 /* Reparse tag is NTFS symlink */
3249 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3250 reparse_buf->PathBuffer;
3251 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3252 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003253 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3254 rc = -EIO;
3255 goto qreparse_out;
3256 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003257 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3258 is_unicode = true;
3259 else
3260 is_unicode = false;
3261
3262 /* BB FIXME investigate remapping reserved chars here */
3263 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3264 nls_codepage);
3265 if (!*symlinkinfo)
3266 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003268 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003270 /*
3271 * Note: On -EAGAIN error only caller can retry on handle based calls
3272 * since file handle passed in no longer valid.
3273 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 return rc;
3275}
3276
Steve Frenchc7f508a2013-10-14 15:27:32 -05003277int
3278CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3279 __u16 fid)
3280{
3281 int rc = 0;
3282 int bytes_returned;
3283 struct smb_com_transaction_compr_ioctl_req *pSMB;
3284 struct smb_com_transaction_ioctl_rsp *pSMBr;
3285
3286 cifs_dbg(FYI, "Set compression for %u\n", fid);
3287 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3288 (void **) &pSMBr);
3289 if (rc)
3290 return rc;
3291
3292 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3293
3294 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003295 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003296 pSMB->MaxParameterCount = 0;
3297 pSMB->MaxDataCount = 0;
3298 pSMB->MaxSetupCount = 4;
3299 pSMB->Reserved = 0;
3300 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003301 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003302 pSMB->DataOffset =
3303 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3304 compression_state) - 4); /* 84 */
3305 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003306 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003307 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003308 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003309 pSMB->IsFsctl = 1; /* FSCTL */
3310 pSMB->IsRootFlag = 0;
3311 pSMB->Fid = fid; /* file handle always le */
3312 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003313 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003314 inc_rfc1001_len(pSMB, 5);
3315
3316 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3317 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3318 if (rc)
3319 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3320
3321 cifs_buf_release(pSMB);
3322
3323 /*
3324 * Note: On -EAGAIN error only caller can retry on handle based calls
3325 * since file handle passed in no longer valid.
3326 */
3327 return rc;
3328}
3329
3330
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331#ifdef CONFIG_CIFS_POSIX
3332
3333/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003334static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003335 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336{
3337 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003338 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3339 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3340 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003341/*
3342 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3343 ace->e_perm, ace->e_tag, ace->e_id);
3344*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
3346 return;
3347}
3348
3349/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003350static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3351 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352{
3353 int size = 0;
3354 int i;
3355 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003356 struct cifs_posix_ace *pACE;
3357 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003358 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
3360 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3361 return -EOPNOTSUPP;
3362
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003363 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 count = le16_to_cpu(cifs_acl->access_entry_count);
3365 pACE = &cifs_acl->ace_array[0];
3366 size = sizeof(struct cifs_posix_acl);
3367 size += sizeof(struct cifs_posix_ace) * count;
3368 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003369 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003370 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3371 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 return -EINVAL;
3373 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003374 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 count = le16_to_cpu(cifs_acl->access_entry_count);
3376 size = sizeof(struct cifs_posix_acl);
3377 size += sizeof(struct cifs_posix_ace) * count;
3378/* skip past access ACEs to get to default ACEs */
3379 pACE = &cifs_acl->ace_array[count];
3380 count = le16_to_cpu(cifs_acl->default_entry_count);
3381 size += sizeof(struct cifs_posix_ace) * count;
3382 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003383 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 return -EINVAL;
3385 } else {
3386 /* illegal type */
3387 return -EINVAL;
3388 }
3389
3390 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003391 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003392 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003393 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 return -ERANGE;
3395 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003396 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3397
Steve Frenchff7feac2005-11-15 16:45:16 -08003398 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003399 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003400 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003401 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 }
3403 }
3404 return size;
3405}
3406
Steve French50c2f752007-07-13 00:33:32 +00003407static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003408 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409{
3410 __u16 rc = 0; /* 0 = ACL converted ok */
3411
Steve Frenchff7feac2005-11-15 16:45:16 -08003412 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3413 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003415 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 /* Probably no need to le convert -1 on any arch but can not hurt */
3417 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003418 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003419 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003420/*
3421 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3422 ace->e_perm, ace->e_tag, ace->e_id);
3423*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 return rc;
3425}
3426
3427/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003428static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3429 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430{
3431 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003432 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003433 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003434 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 int count;
3436 int i;
3437
Steve French790fe572007-07-07 19:25:05 +00003438 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 return 0;
3440
3441 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003442 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3443 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003444 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003445 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3446 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 return 0;
3448 }
3449 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003450 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003451 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003452 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003453 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003454 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003455 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003456 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003457 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 return 0;
3459 }
Steve French50c2f752007-07-13 00:33:32 +00003460 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003461 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003462 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 /* ACE not converted */
3464 break;
3465 }
3466 }
Steve French790fe572007-07-07 19:25:05 +00003467 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3469 rc += sizeof(struct cifs_posix_acl);
3470 /* BB add check to make sure ACL does not overflow SMB */
3471 }
3472 return rc;
3473}
3474
3475int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003476CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003477 const unsigned char *searchName,
3478 char *acl_inf, const int buflen, const int acl_type,
3479 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480{
3481/* SMB_QUERY_POSIX_ACL */
3482 TRANSACTION2_QPI_REQ *pSMB = NULL;
3483 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3484 int rc = 0;
3485 int bytes_returned;
3486 int name_len;
3487 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003488
Joe Perchesf96637b2013-05-04 22:12:25 -05003489 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
3491queryAclRetry:
3492 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3493 (void **) &pSMBr);
3494 if (rc)
3495 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003496
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3498 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003499 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3500 searchName, PATH_MAX, nls_codepage,
3501 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 name_len++; /* trailing null */
3503 name_len *= 2;
3504 pSMB->FileName[name_len] = 0;
3505 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003506 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 name_len = strnlen(searchName, PATH_MAX);
3508 name_len++; /* trailing null */
3509 strncpy(pSMB->FileName, searchName, name_len);
3510 }
3511
3512 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3513 pSMB->TotalDataCount = 0;
3514 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003515 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 pSMB->MaxDataCount = cpu_to_le16(4000);
3517 pSMB->MaxSetupCount = 0;
3518 pSMB->Reserved = 0;
3519 pSMB->Flags = 0;
3520 pSMB->Timeout = 0;
3521 pSMB->Reserved2 = 0;
3522 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003523 offsetof(struct smb_com_transaction2_qpi_req,
3524 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 pSMB->DataCount = 0;
3526 pSMB->DataOffset = 0;
3527 pSMB->SetupCount = 1;
3528 pSMB->Reserved3 = 0;
3529 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3530 byte_count = params + 1 /* pad */ ;
3531 pSMB->TotalParameterCount = cpu_to_le16(params);
3532 pSMB->ParameterCount = pSMB->TotalParameterCount;
3533 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3534 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003535 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 pSMB->ByteCount = cpu_to_le16(byte_count);
3537
3538 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3539 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003540 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003542 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 } else {
3544 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003545
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003548 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 rc = -EIO; /* bad smb */
3550 else {
3551 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3552 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3553 rc = cifs_copy_posix_acl(acl_inf,
3554 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003555 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 }
3557 }
3558 cifs_buf_release(pSMB);
3559 if (rc == -EAGAIN)
3560 goto queryAclRetry;
3561 return rc;
3562}
3563
3564int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003565CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003566 const unsigned char *fileName,
3567 const char *local_acl, const int buflen,
3568 const int acl_type,
3569 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570{
3571 struct smb_com_transaction2_spi_req *pSMB = NULL;
3572 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3573 char *parm_data;
3574 int name_len;
3575 int rc = 0;
3576 int bytes_returned = 0;
3577 __u16 params, byte_count, data_count, param_offset, offset;
3578
Joe Perchesf96637b2013-05-04 22:12:25 -05003579 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580setAclRetry:
3581 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003582 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 if (rc)
3584 return rc;
3585 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3586 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003587 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3588 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 name_len++; /* trailing null */
3590 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003591 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 name_len = strnlen(fileName, PATH_MAX);
3593 name_len++; /* trailing null */
3594 strncpy(pSMB->FileName, fileName, name_len);
3595 }
3596 params = 6 + name_len;
3597 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003598 /* BB find max SMB size from sess */
3599 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 pSMB->MaxSetupCount = 0;
3601 pSMB->Reserved = 0;
3602 pSMB->Flags = 0;
3603 pSMB->Timeout = 0;
3604 pSMB->Reserved2 = 0;
3605 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003606 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 offset = param_offset + params;
3608 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3609 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3610
3611 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003612 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613
Steve French790fe572007-07-07 19:25:05 +00003614 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 rc = -EOPNOTSUPP;
3616 goto setACLerrorExit;
3617 }
3618 pSMB->DataOffset = cpu_to_le16(offset);
3619 pSMB->SetupCount = 1;
3620 pSMB->Reserved3 = 0;
3621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3622 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3623 byte_count = 3 /* pad */ + params + data_count;
3624 pSMB->DataCount = cpu_to_le16(data_count);
3625 pSMB->TotalDataCount = pSMB->DataCount;
3626 pSMB->ParameterCount = cpu_to_le16(params);
3627 pSMB->TotalParameterCount = pSMB->ParameterCount;
3628 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003629 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 pSMB->ByteCount = cpu_to_le16(byte_count);
3631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003633 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003634 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635
3636setACLerrorExit:
3637 cifs_buf_release(pSMB);
3638 if (rc == -EAGAIN)
3639 goto setAclRetry;
3640 return rc;
3641}
3642
Steve Frenchf654bac2005-04-28 22:41:04 -07003643/* BB fix tabs in this function FIXME BB */
3644int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003645CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003646 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003647{
Steve French50c2f752007-07-13 00:33:32 +00003648 int rc = 0;
3649 struct smb_t2_qfi_req *pSMB = NULL;
3650 struct smb_t2_qfi_rsp *pSMBr = NULL;
3651 int bytes_returned;
3652 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003653
Joe Perchesf96637b2013-05-04 22:12:25 -05003654 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003655 if (tcon == NULL)
3656 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003657
3658GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003659 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3660 (void **) &pSMBr);
3661 if (rc)
3662 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003663
Steve Frenchad7a2922008-02-07 23:25:02 +00003664 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003665 pSMB->t2.TotalDataCount = 0;
3666 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3667 /* BB find exact max data count below from sess structure BB */
3668 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3669 pSMB->t2.MaxSetupCount = 0;
3670 pSMB->t2.Reserved = 0;
3671 pSMB->t2.Flags = 0;
3672 pSMB->t2.Timeout = 0;
3673 pSMB->t2.Reserved2 = 0;
3674 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3675 Fid) - 4);
3676 pSMB->t2.DataCount = 0;
3677 pSMB->t2.DataOffset = 0;
3678 pSMB->t2.SetupCount = 1;
3679 pSMB->t2.Reserved3 = 0;
3680 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3681 byte_count = params + 1 /* pad */ ;
3682 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3683 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3684 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3685 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003686 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003687 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003688 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003689
Steve French790fe572007-07-07 19:25:05 +00003690 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3691 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3692 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003693 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003694 } else {
3695 /* decode response */
3696 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003697 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003698 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003699 /* If rc should we check for EOPNOSUPP and
3700 disable the srvino flag? or in caller? */
3701 rc = -EIO; /* bad smb */
3702 else {
3703 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3704 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3705 struct file_chattr_info *pfinfo;
3706 /* BB Do we need a cast or hash here ? */
3707 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003708 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003709 rc = -EIO;
3710 goto GetExtAttrOut;
3711 }
3712 pfinfo = (struct file_chattr_info *)
3713 (data_offset + (char *) &pSMBr->hdr.Protocol);
3714 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003715 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003716 }
3717 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003718GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003719 cifs_buf_release(pSMB);
3720 if (rc == -EAGAIN)
3721 goto GetExtAttrRetry;
3722 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003723}
3724
Steve Frenchf654bac2005-04-28 22:41:04 -07003725#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726
Jeff Layton79df1ba2010-12-06 12:52:08 -05003727#ifdef CONFIG_CIFS_ACL
3728/*
3729 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3730 * all NT TRANSACTS that we init here have total parm and data under about 400
3731 * bytes (to fit in small cifs buffer size), which is the case so far, it
3732 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3733 * returned setup area) and MaxParameterCount (returned parms size) must be set
3734 * by caller
3735 */
3736static int
3737smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003738 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003739 void **ret_buf)
3740{
3741 int rc;
3742 __u32 temp_offset;
3743 struct smb_com_ntransact_req *pSMB;
3744
3745 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3746 (void **)&pSMB);
3747 if (rc)
3748 return rc;
3749 *ret_buf = (void *)pSMB;
3750 pSMB->Reserved = 0;
3751 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3752 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003753 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003754 pSMB->ParameterCount = pSMB->TotalParameterCount;
3755 pSMB->DataCount = pSMB->TotalDataCount;
3756 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3757 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3758 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3759 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3760 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3761 pSMB->SubCommand = cpu_to_le16(sub_command);
3762 return 0;
3763}
3764
3765static int
3766validate_ntransact(char *buf, char **ppparm, char **ppdata,
3767 __u32 *pparmlen, __u32 *pdatalen)
3768{
3769 char *end_of_smb;
3770 __u32 data_count, data_offset, parm_count, parm_offset;
3771 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003772 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003773
3774 *pdatalen = 0;
3775 *pparmlen = 0;
3776
3777 if (buf == NULL)
3778 return -EINVAL;
3779
3780 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3781
Jeff Layton820a8032011-05-04 08:05:26 -04003782 bcc = get_bcc(&pSMBr->hdr);
3783 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003784 (char *)&pSMBr->ByteCount;
3785
3786 data_offset = le32_to_cpu(pSMBr->DataOffset);
3787 data_count = le32_to_cpu(pSMBr->DataCount);
3788 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3789 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3790
3791 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3792 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3793
3794 /* should we also check that parm and data areas do not overlap? */
3795 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003796 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003797 return -EINVAL;
3798 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003799 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003800 return -EINVAL;
3801 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003802 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003803 return -EINVAL;
3804 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003805 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3806 *ppdata, data_count, (data_count + *ppdata),
3807 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003808 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003809 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003810 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003811 return -EINVAL;
3812 }
3813 *pdatalen = data_count;
3814 *pparmlen = parm_count;
3815 return 0;
3816}
3817
Steve French0a4b92c2006-01-12 15:44:21 -08003818/* Get Security Descriptor (by handle) from remote server for a file or dir */
3819int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003820CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003821 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003822{
3823 int rc = 0;
3824 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003825 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003826 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003827 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003828
Joe Perchesf96637b2013-05-04 22:12:25 -05003829 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003830
Steve French630f3f0c2007-10-25 21:17:17 +00003831 *pbuflen = 0;
3832 *acl_inf = NULL;
3833
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003834 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003835 8 /* parm len */, tcon, (void **) &pSMB);
3836 if (rc)
3837 return rc;
3838
3839 pSMB->MaxParameterCount = cpu_to_le32(4);
3840 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3841 pSMB->MaxSetupCount = 0;
3842 pSMB->Fid = fid; /* file handle always le */
3843 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3844 CIFS_ACL_DACL);
3845 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003846 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003847 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003848 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003849
Steve Frencha761ac52007-10-18 21:45:27 +00003850 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003851 0, &rsp_iov);
3852 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003853 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003854 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003855 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003856 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003857 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003858 __u32 parm_len;
3859 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003860 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003861 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003862
3863/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003864 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003865 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003866 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003867 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003868 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003869
Joe Perchesf96637b2013-05-04 22:12:25 -05003870 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3871 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003872
3873 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3874 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003875 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003876 goto qsec_out;
3877 }
3878
3879/* BB check that data area is minimum length and as big as acl_len */
3880
Steve Frenchaf6f4612007-10-16 18:40:37 +00003881 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003882 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003883 cifs_dbg(VFS, "acl length %d does not match %d\n",
3884 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003885 if (*pbuflen > acl_len)
3886 *pbuflen = acl_len;
3887 }
Steve French0a4b92c2006-01-12 15:44:21 -08003888
Steve French630f3f0c2007-10-25 21:17:17 +00003889 /* check if buffer is big enough for the acl
3890 header followed by the smallest SID */
3891 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3892 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003893 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003894 rc = -EINVAL;
3895 *pbuflen = 0;
3896 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003897 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003898 if (*acl_inf == NULL) {
3899 *pbuflen = 0;
3900 rc = -ENOMEM;
3901 }
Steve French630f3f0c2007-10-25 21:17:17 +00003902 }
Steve French0a4b92c2006-01-12 15:44:21 -08003903 }
3904qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003905 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003906 return rc;
3907}
Steve French97837582007-12-31 07:47:21 +00003908
3909int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003910CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003911 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003912{
3913 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3914 int rc = 0;
3915 int bytes_returned = 0;
3916 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003917 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003918
3919setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003920 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003921 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003922 return rc;
Steve French97837582007-12-31 07:47:21 +00003923
3924 pSMB->MaxSetupCount = 0;
3925 pSMB->Reserved = 0;
3926
3927 param_count = 8;
3928 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3929 data_count = acllen;
3930 data_offset = param_offset + param_count;
3931 byte_count = 3 /* pad */ + param_count;
3932
3933 pSMB->DataCount = cpu_to_le32(data_count);
3934 pSMB->TotalDataCount = pSMB->DataCount;
3935 pSMB->MaxParameterCount = cpu_to_le32(4);
3936 pSMB->MaxDataCount = cpu_to_le32(16384);
3937 pSMB->ParameterCount = cpu_to_le32(param_count);
3938 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3939 pSMB->TotalParameterCount = pSMB->ParameterCount;
3940 pSMB->DataOffset = cpu_to_le32(data_offset);
3941 pSMB->SetupCount = 0;
3942 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3943 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3944
3945 pSMB->Fid = fid; /* file handle always le */
3946 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003947 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003948
3949 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003950 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3951 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003952 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003953 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003954 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003955
3956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3958
Joe Perchesf96637b2013-05-04 22:12:25 -05003959 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3960 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003961 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003962 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003963 cifs_buf_release(pSMB);
3964
3965 if (rc == -EAGAIN)
3966 goto setCifsAclRetry;
3967
3968 return (rc);
3969}
3970
Jeff Layton79df1ba2010-12-06 12:52:08 -05003971#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003972
Steve French6b8edfe2005-08-23 20:26:03 -07003973/* Legacy Query Path Information call for lookup to old servers such
3974 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003975int
3976SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3977 const char *search_name, FILE_ALL_INFO *data,
3978 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003979{
Steve Frenchad7a2922008-02-07 23:25:02 +00003980 QUERY_INFORMATION_REQ *pSMB;
3981 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003982 int rc = 0;
3983 int bytes_returned;
3984 int name_len;
3985
Joe Perchesf96637b2013-05-04 22:12:25 -05003986 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003987QInfRetry:
3988 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003989 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003990 if (rc)
3991 return rc;
3992
3993 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3994 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003995 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003996 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003997 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003998 name_len++; /* trailing null */
3999 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004000 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004001 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004002 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004003 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004004 }
4005 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004006 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004007 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004008 pSMB->ByteCount = cpu_to_le16(name_len);
4009
4010 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004011 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004012 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004013 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004014 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004015 struct timespec ts;
4016 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004017
4018 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004019 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004020 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004021 ts.tv_nsec = 0;
4022 ts.tv_sec = time;
4023 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004024 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4025 data->LastWriteTime = data->ChangeTime;
4026 data->LastAccessTime = 0;
4027 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004028 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004029 data->EndOfFile = data->AllocationSize;
4030 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004031 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004032 } else
4033 rc = -EIO; /* bad buffer passed in */
4034
4035 cifs_buf_release(pSMB);
4036
4037 if (rc == -EAGAIN)
4038 goto QInfRetry;
4039
4040 return rc;
4041}
4042
Jeff Laytonbcd53572010-02-12 07:44:16 -05004043int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004044CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004045 u16 netfid, FILE_ALL_INFO *pFindData)
4046{
4047 struct smb_t2_qfi_req *pSMB = NULL;
4048 struct smb_t2_qfi_rsp *pSMBr = NULL;
4049 int rc = 0;
4050 int bytes_returned;
4051 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004052
Jeff Laytonbcd53572010-02-12 07:44:16 -05004053QFileInfoRetry:
4054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4055 (void **) &pSMBr);
4056 if (rc)
4057 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004058
Jeff Laytonbcd53572010-02-12 07:44:16 -05004059 params = 2 /* level */ + 2 /* fid */;
4060 pSMB->t2.TotalDataCount = 0;
4061 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4062 /* BB find exact max data count below from sess structure BB */
4063 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4064 pSMB->t2.MaxSetupCount = 0;
4065 pSMB->t2.Reserved = 0;
4066 pSMB->t2.Flags = 0;
4067 pSMB->t2.Timeout = 0;
4068 pSMB->t2.Reserved2 = 0;
4069 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4070 Fid) - 4);
4071 pSMB->t2.DataCount = 0;
4072 pSMB->t2.DataOffset = 0;
4073 pSMB->t2.SetupCount = 1;
4074 pSMB->t2.Reserved3 = 0;
4075 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4076 byte_count = params + 1 /* pad */ ;
4077 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4078 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4079 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4080 pSMB->Pad = 0;
4081 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004082 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004083 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004084
4085 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4086 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4087 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004088 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004089 } else { /* decode response */
4090 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4091
4092 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4093 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004094 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004095 rc = -EIO; /* bad smb */
4096 else if (pFindData) {
4097 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4098 memcpy((char *) pFindData,
4099 (char *) &pSMBr->hdr.Protocol +
4100 data_offset, sizeof(FILE_ALL_INFO));
4101 } else
4102 rc = -ENOMEM;
4103 }
4104 cifs_buf_release(pSMB);
4105 if (rc == -EAGAIN)
4106 goto QFileInfoRetry;
4107
4108 return rc;
4109}
Steve French6b8edfe2005-08-23 20:26:03 -07004110
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004112CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004113 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004114 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004115 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004117 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 TRANSACTION2_QPI_REQ *pSMB = NULL;
4119 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4120 int rc = 0;
4121 int bytes_returned;
4122 int name_len;
4123 __u16 params, byte_count;
4124
Joe Perchesf96637b2013-05-04 22:12:25 -05004125 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126QPathInfoRetry:
4127 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4128 (void **) &pSMBr);
4129 if (rc)
4130 return rc;
4131
4132 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4133 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004134 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004135 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 name_len++; /* trailing null */
4137 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004138 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004139 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004141 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 }
4143
Steve French50c2f752007-07-13 00:33:32 +00004144 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 pSMB->TotalDataCount = 0;
4146 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004147 /* BB find exact max SMB PDU from sess structure BB */
4148 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 pSMB->MaxSetupCount = 0;
4150 pSMB->Reserved = 0;
4151 pSMB->Flags = 0;
4152 pSMB->Timeout = 0;
4153 pSMB->Reserved2 = 0;
4154 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004155 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 pSMB->DataCount = 0;
4157 pSMB->DataOffset = 0;
4158 pSMB->SetupCount = 1;
4159 pSMB->Reserved3 = 0;
4160 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4161 byte_count = params + 1 /* pad */ ;
4162 pSMB->TotalParameterCount = cpu_to_le16(params);
4163 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004164 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004165 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4166 else
4167 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004169 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 pSMB->ByteCount = cpu_to_le16(byte_count);
4171
4172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4174 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004175 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 } else { /* decode response */
4177 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4178
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004179 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4180 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004181 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004183 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004184 rc = -EIO; /* 24 or 26 expected but we do not read
4185 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004186 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004187 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004189
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004190 /*
4191 * On legacy responses we do not read the last field,
4192 * EAsize, fortunately since it varies by subdialect and
4193 * also note it differs on Set vs Get, ie two bytes or 4
4194 * bytes depending but we don't care here.
4195 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004196 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004197 size = sizeof(FILE_INFO_STANDARD);
4198 else
4199 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004200 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004201 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 } else
4203 rc = -ENOMEM;
4204 }
4205 cifs_buf_release(pSMB);
4206 if (rc == -EAGAIN)
4207 goto QPathInfoRetry;
4208
4209 return rc;
4210}
4211
4212int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004213CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004214 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4215{
4216 struct smb_t2_qfi_req *pSMB = NULL;
4217 struct smb_t2_qfi_rsp *pSMBr = NULL;
4218 int rc = 0;
4219 int bytes_returned;
4220 __u16 params, byte_count;
4221
4222UnixQFileInfoRetry:
4223 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4224 (void **) &pSMBr);
4225 if (rc)
4226 return rc;
4227
4228 params = 2 /* level */ + 2 /* fid */;
4229 pSMB->t2.TotalDataCount = 0;
4230 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4231 /* BB find exact max data count below from sess structure BB */
4232 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4233 pSMB->t2.MaxSetupCount = 0;
4234 pSMB->t2.Reserved = 0;
4235 pSMB->t2.Flags = 0;
4236 pSMB->t2.Timeout = 0;
4237 pSMB->t2.Reserved2 = 0;
4238 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4239 Fid) - 4);
4240 pSMB->t2.DataCount = 0;
4241 pSMB->t2.DataOffset = 0;
4242 pSMB->t2.SetupCount = 1;
4243 pSMB->t2.Reserved3 = 0;
4244 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4245 byte_count = params + 1 /* pad */ ;
4246 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4247 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4248 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4249 pSMB->Pad = 0;
4250 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004251 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004252 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004253
4254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4256 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004257 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004258 } else { /* decode response */
4259 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4260
Jeff Layton820a8032011-05-04 08:05:26 -04004261 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004262 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 -05004263 rc = -EIO; /* bad smb */
4264 } else {
4265 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4266 memcpy((char *) pFindData,
4267 (char *) &pSMBr->hdr.Protocol +
4268 data_offset,
4269 sizeof(FILE_UNIX_BASIC_INFO));
4270 }
4271 }
4272
4273 cifs_buf_release(pSMB);
4274 if (rc == -EAGAIN)
4275 goto UnixQFileInfoRetry;
4276
4277 return rc;
4278}
4279
4280int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004281CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004283 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004284 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285{
4286/* SMB_QUERY_FILE_UNIX_BASIC */
4287 TRANSACTION2_QPI_REQ *pSMB = NULL;
4288 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4289 int rc = 0;
4290 int bytes_returned = 0;
4291 int name_len;
4292 __u16 params, byte_count;
4293
Joe Perchesf96637b2013-05-04 22:12:25 -05004294 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295UnixQPathInfoRetry:
4296 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4297 (void **) &pSMBr);
4298 if (rc)
4299 return rc;
4300
4301 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4302 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004303 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4304 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 name_len++; /* trailing null */
4306 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004307 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 name_len = strnlen(searchName, PATH_MAX);
4309 name_len++; /* trailing null */
4310 strncpy(pSMB->FileName, searchName, name_len);
4311 }
4312
Steve French50c2f752007-07-13 00:33:32 +00004313 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 pSMB->TotalDataCount = 0;
4315 pSMB->MaxParameterCount = cpu_to_le16(2);
4316 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004317 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 pSMB->MaxSetupCount = 0;
4319 pSMB->Reserved = 0;
4320 pSMB->Flags = 0;
4321 pSMB->Timeout = 0;
4322 pSMB->Reserved2 = 0;
4323 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004324 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 pSMB->DataCount = 0;
4326 pSMB->DataOffset = 0;
4327 pSMB->SetupCount = 1;
4328 pSMB->Reserved3 = 0;
4329 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4330 byte_count = params + 1 /* pad */ ;
4331 pSMB->TotalParameterCount = cpu_to_le16(params);
4332 pSMB->ParameterCount = pSMB->TotalParameterCount;
4333 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4334 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004335 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 pSMB->ByteCount = cpu_to_le16(byte_count);
4337
4338 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4339 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4340 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004341 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 } else { /* decode response */
4343 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4344
Jeff Layton820a8032011-05-04 08:05:26 -04004345 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004346 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 -07004347 rc = -EIO; /* bad smb */
4348 } else {
4349 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4350 memcpy((char *) pFindData,
4351 (char *) &pSMBr->hdr.Protocol +
4352 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004353 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 }
4355 }
4356 cifs_buf_release(pSMB);
4357 if (rc == -EAGAIN)
4358 goto UnixQPathInfoRetry;
4359
4360 return rc;
4361}
4362
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363/* xid, tcon, searchName and codepage are input parms, rest are returned */
4364int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004365CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004366 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004367 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004368 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369{
4370/* level 257 SMB_ */
4371 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4372 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004373 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 int rc = 0;
4375 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004376 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004378 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
Joe Perchesf96637b2013-05-04 22:12:25 -05004380 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
4382findFirstRetry:
4383 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4384 (void **) &pSMBr);
4385 if (rc)
4386 return rc;
4387
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004388 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004389 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004390
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4392 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004393 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4394 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004395 /* We can not add the asterik earlier in case
4396 it got remapped to 0xF03A as if it were part of the
4397 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004399 if (msearch) {
4400 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4401 pSMB->FileName[name_len+1] = 0;
4402 pSMB->FileName[name_len+2] = '*';
4403 pSMB->FileName[name_len+3] = 0;
4404 name_len += 4; /* now the trailing null */
4405 /* null terminate just in case */
4406 pSMB->FileName[name_len] = 0;
4407 pSMB->FileName[name_len+1] = 0;
4408 name_len += 2;
4409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 } else { /* BB add check for overrun of SMB buf BB */
4411 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004413 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 free buffer exit; BB */
4415 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004416 if (msearch) {
4417 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4418 pSMB->FileName[name_len+1] = '*';
4419 pSMB->FileName[name_len+2] = 0;
4420 name_len += 3;
4421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 }
4423
4424 params = 12 + name_len /* includes null */ ;
4425 pSMB->TotalDataCount = 0; /* no EAs */
4426 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004427 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 pSMB->MaxSetupCount = 0;
4429 pSMB->Reserved = 0;
4430 pSMB->Flags = 0;
4431 pSMB->Timeout = 0;
4432 pSMB->Reserved2 = 0;
4433 byte_count = params + 1 /* pad */ ;
4434 pSMB->TotalParameterCount = cpu_to_le16(params);
4435 pSMB->ParameterCount = pSMB->TotalParameterCount;
4436 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004437 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4438 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 pSMB->DataCount = 0;
4440 pSMB->DataOffset = 0;
4441 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4442 pSMB->Reserved3 = 0;
4443 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4444 pSMB->SearchAttributes =
4445 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4446 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004447 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004448 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4450
4451 /* BB what should we set StorageType to? Does it matter? BB */
4452 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004453 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 pSMB->ByteCount = cpu_to_le16(byte_count);
4455
4456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004458 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
Steve French88274812006-03-09 22:21:45 +00004460 if (rc) {/* BB add logic to retry regular search if Unix search
4461 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004463 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004464
Steve French88274812006-03-09 22:21:45 +00004465 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466
4467 /* BB eventually could optimize out free and realloc of buf */
4468 /* for this case */
4469 if (rc == -EAGAIN)
4470 goto findFirstRetry;
4471 } else { /* decode response */
4472 /* BB remember to free buffer if error BB */
4473 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004474 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004475 unsigned int lnoff;
4476
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004478 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 else
Steve French4b18f2a2008-04-29 00:06:05 +00004480 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481
4482 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004483 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004484 psrch_inf->srch_entries_start =
4485 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4488 le16_to_cpu(pSMBr->t2.ParameterOffset));
4489
Steve French790fe572007-07-07 19:25:05 +00004490 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004491 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 else
Steve French4b18f2a2008-04-29 00:06:05 +00004493 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Steve French50c2f752007-07-13 00:33:32 +00004495 psrch_inf->entries_in_buffer =
4496 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004497 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004499 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004500 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004501 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004502 psrch_inf->last_entry = NULL;
4503 return rc;
4504 }
4505
Steve French0752f152008-10-07 20:03:33 +00004506 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004507 lnoff;
4508
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004509 if (pnetfid)
4510 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 } else {
4512 cifs_buf_release(pSMB);
4513 }
4514 }
4515
4516 return rc;
4517}
4518
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004519int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4520 __u16 searchHandle, __u16 search_flags,
4521 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522{
4523 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4524 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004525 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 char *response_data;
4527 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004528 int bytes_returned;
4529 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 __u16 params, byte_count;
4531
Joe Perchesf96637b2013-05-04 22:12:25 -05004532 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533
Steve French4b18f2a2008-04-29 00:06:05 +00004534 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 return -ENOENT;
4536
4537 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4538 (void **) &pSMBr);
4539 if (rc)
4540 return rc;
4541
Steve French50c2f752007-07-13 00:33:32 +00004542 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 byte_count = 0;
4544 pSMB->TotalDataCount = 0; /* no EAs */
4545 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004546 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 pSMB->MaxSetupCount = 0;
4548 pSMB->Reserved = 0;
4549 pSMB->Flags = 0;
4550 pSMB->Timeout = 0;
4551 pSMB->Reserved2 = 0;
4552 pSMB->ParameterOffset = cpu_to_le16(
4553 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4554 pSMB->DataCount = 0;
4555 pSMB->DataOffset = 0;
4556 pSMB->SetupCount = 1;
4557 pSMB->Reserved3 = 0;
4558 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4559 pSMB->SearchHandle = searchHandle; /* always kept as le */
4560 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004561 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4563 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004564 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565
4566 name_len = psrch_inf->resume_name_len;
4567 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004568 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4570 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004571 /* 14 byte parm len above enough for 2 byte null terminator */
4572 pSMB->ResumeFileName[name_len] = 0;
4573 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 } else {
4575 rc = -EINVAL;
4576 goto FNext2_err_exit;
4577 }
4578 byte_count = params + 1 /* pad */ ;
4579 pSMB->TotalParameterCount = cpu_to_le16(params);
4580 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004581 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004586 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 if (rc) {
4588 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004589 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004590 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004591 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004593 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 } else { /* decode response */
4595 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004596
Steve French790fe572007-07-07 19:25:05 +00004597 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004598 unsigned int lnoff;
4599
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 /* BB fixme add lock for file (srch_info) struct here */
4601 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004602 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 else
Steve French4b18f2a2008-04-29 00:06:05 +00004604 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 response_data = (char *) &pSMBr->hdr.Protocol +
4606 le16_to_cpu(pSMBr->t2.ParameterOffset);
4607 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4608 response_data = (char *)&pSMBr->hdr.Protocol +
4609 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004610 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004611 cifs_small_buf_release(
4612 psrch_inf->ntwrk_buf_start);
4613 else
4614 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 psrch_inf->srch_entries_start = response_data;
4616 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004617 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004618 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004619 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 else
Steve French4b18f2a2008-04-29 00:06:05 +00004621 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004622 psrch_inf->entries_in_buffer =
4623 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 psrch_inf->index_of_last_entry +=
4625 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004626 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004627 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004628 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004629 psrch_inf->last_entry = NULL;
4630 return rc;
4631 } else
4632 psrch_inf->last_entry =
4633 psrch_inf->srch_entries_start + lnoff;
4634
Joe Perchesf96637b2013-05-04 22:12:25 -05004635/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4636 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637
4638 /* BB fixme add unlock here */
4639 }
4640
4641 }
4642
4643 /* BB On error, should we leave previous search buf (and count and
4644 last entry fields) intact or free the previous one? */
4645
4646 /* Note: On -EAGAIN error only caller can retry on handle based calls
4647 since file handle passed in no longer valid */
4648FNext2_err_exit:
4649 if (rc != 0)
4650 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 return rc;
4652}
4653
4654int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004655CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004656 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657{
4658 int rc = 0;
4659 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Joe Perchesf96637b2013-05-04 22:12:25 -05004661 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4663
4664 /* no sense returning error if session restarted
4665 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004666 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 return 0;
4668 if (rc)
4669 return rc;
4670
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 pSMB->FileID = searchHandle;
4672 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004673 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004674 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004675 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004676 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004677
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004678 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679
4680 /* Since session is dead, search handle closed on server already */
4681 if (rc == -EAGAIN)
4682 rc = 0;
4683
4684 return rc;
4685}
4686
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004688CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004689 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004690 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
4692 int rc = 0;
4693 TRANSACTION2_QPI_REQ *pSMB = NULL;
4694 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4695 int name_len, bytes_returned;
4696 __u16 params, byte_count;
4697
Joe Perchesf96637b2013-05-04 22:12:25 -05004698 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004699 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004700 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701
4702GetInodeNumberRetry:
4703 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004704 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 if (rc)
4706 return rc;
4707
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4709 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004710 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004711 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004712 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 name_len++; /* trailing null */
4714 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004715 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004716 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004718 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 }
4720
4721 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4722 pSMB->TotalDataCount = 0;
4723 pSMB->MaxParameterCount = cpu_to_le16(2);
4724 /* BB find exact max data count below from sess structure BB */
4725 pSMB->MaxDataCount = cpu_to_le16(4000);
4726 pSMB->MaxSetupCount = 0;
4727 pSMB->Reserved = 0;
4728 pSMB->Flags = 0;
4729 pSMB->Timeout = 0;
4730 pSMB->Reserved2 = 0;
4731 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004732 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 pSMB->DataCount = 0;
4734 pSMB->DataOffset = 0;
4735 pSMB->SetupCount = 1;
4736 pSMB->Reserved3 = 0;
4737 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4738 byte_count = params + 1 /* pad */ ;
4739 pSMB->TotalParameterCount = cpu_to_le16(params);
4740 pSMB->ParameterCount = pSMB->TotalParameterCount;
4741 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4742 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004743 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 pSMB->ByteCount = cpu_to_le16(byte_count);
4745
4746 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4747 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4748 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004749 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 } else {
4751 /* decode response */
4752 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004754 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 /* If rc should we check for EOPNOSUPP and
4756 disable the srvino flag? or in caller? */
4757 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004758 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4760 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004761 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004763 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004764 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 rc = -EIO;
4766 goto GetInodeNumOut;
4767 }
4768 pfinfo = (struct file_internal_info *)
4769 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004770 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 }
4772 }
4773GetInodeNumOut:
4774 cifs_buf_release(pSMB);
4775 if (rc == -EAGAIN)
4776 goto GetInodeNumberRetry;
4777 return rc;
4778}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779
Igor Mammedovfec45852008-05-16 13:06:30 +04004780/* parses DFS refferal V3 structure
4781 * caller is responsible for freeing target_nodes
4782 * returns:
4783 * on success - 0
4784 * on failure - errno
4785 */
4786static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004787parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004788 unsigned int *num_of_nodes,
4789 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004790 const struct nls_table *nls_codepage, int remap,
4791 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004792{
4793 int i, rc = 0;
4794 char *data_end;
4795 bool is_unicode;
4796 struct dfs_referral_level_3 *ref;
4797
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004798 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4799 is_unicode = true;
4800 else
4801 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004802 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4803
4804 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004805 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4806 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004807 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004808 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004809 }
4810
4811 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004812 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004813 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4814 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004815 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004816 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004817 }
4818
4819 /* get the upper boundary of the resp buffer */
4820 data_end = (char *)(&(pSMBr->PathConsumed)) +
4821 le16_to_cpu(pSMBr->t2.DataCount);
4822
Joe Perchesf96637b2013-05-04 22:12:25 -05004823 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4824 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004825
Joe Perchesf96637b2013-05-04 22:12:25 -05004826 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4827 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004828 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004829 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004830 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004831 }
4832
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004833 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004834 for (i = 0; i < *num_of_nodes; i++) {
4835 char *temp;
4836 int max_len;
4837 struct dfs_info3_param *node = (*target_nodes)+i;
4838
Steve French0e0d2cf2009-05-01 05:27:32 +00004839 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004840 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004841 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4842 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004843 if (tmp == NULL) {
4844 rc = -ENOMEM;
4845 goto parse_DFS_referrals_exit;
4846 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004847 cifsConvertToUTF16((__le16 *) tmp, searchName,
4848 PATH_MAX, nls_codepage, remap);
4849 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004850 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004851 nls_codepage);
4852 kfree(tmp);
4853 } else
4854 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4855
Igor Mammedovfec45852008-05-16 13:06:30 +04004856 node->server_type = le16_to_cpu(ref->ServerType);
4857 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4858
4859 /* copy DfsPath */
4860 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4861 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004862 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4863 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004864 if (!node->path_name) {
4865 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004866 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004867 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004868
4869 /* copy link target UNC */
4870 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4871 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004872 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4873 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004874 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004875 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004876 goto parse_DFS_referrals_exit;
4877 }
4878
4879 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004880 }
4881
Steve Frencha1fe78f2008-05-16 18:48:38 +00004882parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004883 if (rc) {
4884 free_dfs_info_array(*target_nodes, *num_of_nodes);
4885 *target_nodes = NULL;
4886 *num_of_nodes = 0;
4887 }
4888 return rc;
4889}
4890
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004892CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004893 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004894 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004895 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896{
4897/* TRANS2_GET_DFS_REFERRAL */
4898 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4899 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 int rc = 0;
4901 int bytes_returned;
4902 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004904 *num_of_nodes = 0;
4905 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906
Joe Perchesf96637b2013-05-04 22:12:25 -05004907 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 if (ses == NULL)
4909 return -ENODEV;
4910getDFSRetry:
4911 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4912 (void **) &pSMBr);
4913 if (rc)
4914 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004915
4916 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004917 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004918 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 pSMB->hdr.Tid = ses->ipc_tid;
4920 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004921 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004923 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925
4926 if (ses->capabilities & CAP_UNICODE) {
4927 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4928 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004929 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004930 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004931 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 name_len++; /* trailing null */
4933 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004934 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004935 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004937 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 }
4939
Dan Carpenter65c3b202015-04-30 17:30:24 +03004940 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004941 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004942
Steve French50c2f752007-07-13 00:33:32 +00004943 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004944
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 params = 2 /* level */ + name_len /*includes null */ ;
4946 pSMB->TotalDataCount = 0;
4947 pSMB->DataCount = 0;
4948 pSMB->DataOffset = 0;
4949 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004950 /* BB find exact max SMB PDU from sess structure BB */
4951 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 pSMB->MaxSetupCount = 0;
4953 pSMB->Reserved = 0;
4954 pSMB->Flags = 0;
4955 pSMB->Timeout = 0;
4956 pSMB->Reserved2 = 0;
4957 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004958 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 pSMB->SetupCount = 1;
4960 pSMB->Reserved3 = 0;
4961 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4962 byte_count = params + 3 /* pad */ ;
4963 pSMB->ParameterCount = cpu_to_le16(params);
4964 pSMB->TotalParameterCount = pSMB->ParameterCount;
4965 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004966 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 pSMB->ByteCount = cpu_to_le16(byte_count);
4968
4969 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4971 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004972 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004973 goto GetDFSRefExit;
4974 }
4975 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004977 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004978 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004979 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004980 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004982
Joe Perchesf96637b2013-05-04 22:12:25 -05004983 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4984 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004985
4986 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004987 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004988 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004989 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004990
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004992 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993
4994 if (rc == -EAGAIN)
4995 goto getDFSRetry;
4996
4997 return rc;
4998}
4999
Steve French20962432005-09-21 22:05:57 -07005000/* Query File System Info such as free space to old servers such as Win 9x */
5001int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005002SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5003 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005004{
5005/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5006 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5007 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5008 FILE_SYSTEM_ALLOC_INFO *response_data;
5009 int rc = 0;
5010 int bytes_returned = 0;
5011 __u16 params, byte_count;
5012
Joe Perchesf96637b2013-05-04 22:12:25 -05005013 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005014oldQFSInfoRetry:
5015 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5016 (void **) &pSMBr);
5017 if (rc)
5018 return rc;
Steve French20962432005-09-21 22:05:57 -07005019
5020 params = 2; /* level */
5021 pSMB->TotalDataCount = 0;
5022 pSMB->MaxParameterCount = cpu_to_le16(2);
5023 pSMB->MaxDataCount = cpu_to_le16(1000);
5024 pSMB->MaxSetupCount = 0;
5025 pSMB->Reserved = 0;
5026 pSMB->Flags = 0;
5027 pSMB->Timeout = 0;
5028 pSMB->Reserved2 = 0;
5029 byte_count = params + 1 /* pad */ ;
5030 pSMB->TotalParameterCount = cpu_to_le16(params);
5031 pSMB->ParameterCount = pSMB->TotalParameterCount;
5032 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5033 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5034 pSMB->DataCount = 0;
5035 pSMB->DataOffset = 0;
5036 pSMB->SetupCount = 1;
5037 pSMB->Reserved3 = 0;
5038 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5039 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005040 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005041 pSMB->ByteCount = cpu_to_le16(byte_count);
5042
5043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5045 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005046 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005047 } else { /* decode response */
5048 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5049
Jeff Layton820a8032011-05-04 08:05:26 -04005050 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005051 rc = -EIO; /* bad smb */
5052 else {
5053 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005054 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005055 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005056
Steve French50c2f752007-07-13 00:33:32 +00005057 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005058 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5059 FSData->f_bsize =
5060 le16_to_cpu(response_data->BytesPerSector) *
5061 le32_to_cpu(response_data->
5062 SectorsPerAllocationUnit);
5063 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005064 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005065 FSData->f_bfree = FSData->f_bavail =
5066 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005067 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5068 (unsigned long long)FSData->f_blocks,
5069 (unsigned long long)FSData->f_bfree,
5070 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005071 }
5072 }
5073 cifs_buf_release(pSMB);
5074
5075 if (rc == -EAGAIN)
5076 goto oldQFSInfoRetry;
5077
5078 return rc;
5079}
5080
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005082CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5083 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084{
5085/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5086 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5087 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5088 FILE_SYSTEM_INFO *response_data;
5089 int rc = 0;
5090 int bytes_returned = 0;
5091 __u16 params, byte_count;
5092
Joe Perchesf96637b2013-05-04 22:12:25 -05005093 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094QFSInfoRetry:
5095 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5096 (void **) &pSMBr);
5097 if (rc)
5098 return rc;
5099
5100 params = 2; /* level */
5101 pSMB->TotalDataCount = 0;
5102 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005103 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 pSMB->MaxSetupCount = 0;
5105 pSMB->Reserved = 0;
5106 pSMB->Flags = 0;
5107 pSMB->Timeout = 0;
5108 pSMB->Reserved2 = 0;
5109 byte_count = params + 1 /* pad */ ;
5110 pSMB->TotalParameterCount = cpu_to_le16(params);
5111 pSMB->ParameterCount = pSMB->TotalParameterCount;
5112 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005113 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 pSMB->DataCount = 0;
5115 pSMB->DataOffset = 0;
5116 pSMB->SetupCount = 1;
5117 pSMB->Reserved3 = 0;
5118 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5119 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005120 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 pSMB->ByteCount = cpu_to_le16(byte_count);
5122
5123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5124 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5125 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005126 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005128 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129
Jeff Layton820a8032011-05-04 08:05:26 -04005130 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 rc = -EIO; /* bad smb */
5132 else {
5133 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134
5135 response_data =
5136 (FILE_SYSTEM_INFO
5137 *) (((char *) &pSMBr->hdr.Protocol) +
5138 data_offset);
5139 FSData->f_bsize =
5140 le32_to_cpu(response_data->BytesPerSector) *
5141 le32_to_cpu(response_data->
5142 SectorsPerAllocationUnit);
5143 FSData->f_blocks =
5144 le64_to_cpu(response_data->TotalAllocationUnits);
5145 FSData->f_bfree = FSData->f_bavail =
5146 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005147 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5148 (unsigned long long)FSData->f_blocks,
5149 (unsigned long long)FSData->f_bfree,
5150 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 }
5152 }
5153 cifs_buf_release(pSMB);
5154
5155 if (rc == -EAGAIN)
5156 goto QFSInfoRetry;
5157
5158 return rc;
5159}
5160
5161int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005162CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163{
5164/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5165 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5166 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5167 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5168 int rc = 0;
5169 int bytes_returned = 0;
5170 __u16 params, byte_count;
5171
Joe Perchesf96637b2013-05-04 22:12:25 -05005172 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173QFSAttributeRetry:
5174 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5175 (void **) &pSMBr);
5176 if (rc)
5177 return rc;
5178
5179 params = 2; /* level */
5180 pSMB->TotalDataCount = 0;
5181 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005182 /* BB find exact max SMB PDU from sess structure BB */
5183 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 pSMB->MaxSetupCount = 0;
5185 pSMB->Reserved = 0;
5186 pSMB->Flags = 0;
5187 pSMB->Timeout = 0;
5188 pSMB->Reserved2 = 0;
5189 byte_count = params + 1 /* pad */ ;
5190 pSMB->TotalParameterCount = cpu_to_le16(params);
5191 pSMB->ParameterCount = pSMB->TotalParameterCount;
5192 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005193 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 pSMB->DataCount = 0;
5195 pSMB->DataOffset = 0;
5196 pSMB->SetupCount = 1;
5197 pSMB->Reserved3 = 0;
5198 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5199 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005200 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 pSMB->ByteCount = cpu_to_le16(byte_count);
5202
5203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5205 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005206 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 } else { /* decode response */
5208 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5209
Jeff Layton820a8032011-05-04 08:05:26 -04005210 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005211 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 rc = -EIO; /* bad smb */
5213 } else {
5214 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5215 response_data =
5216 (FILE_SYSTEM_ATTRIBUTE_INFO
5217 *) (((char *) &pSMBr->hdr.Protocol) +
5218 data_offset);
5219 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005220 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 }
5222 }
5223 cifs_buf_release(pSMB);
5224
5225 if (rc == -EAGAIN)
5226 goto QFSAttributeRetry;
5227
5228 return rc;
5229}
5230
5231int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005232CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233{
5234/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5235 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5236 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5237 FILE_SYSTEM_DEVICE_INFO *response_data;
5238 int rc = 0;
5239 int bytes_returned = 0;
5240 __u16 params, byte_count;
5241
Joe Perchesf96637b2013-05-04 22:12:25 -05005242 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243QFSDeviceRetry:
5244 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5245 (void **) &pSMBr);
5246 if (rc)
5247 return rc;
5248
5249 params = 2; /* level */
5250 pSMB->TotalDataCount = 0;
5251 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005252 /* BB find exact max SMB PDU from sess structure BB */
5253 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 pSMB->MaxSetupCount = 0;
5255 pSMB->Reserved = 0;
5256 pSMB->Flags = 0;
5257 pSMB->Timeout = 0;
5258 pSMB->Reserved2 = 0;
5259 byte_count = params + 1 /* pad */ ;
5260 pSMB->TotalParameterCount = cpu_to_le16(params);
5261 pSMB->ParameterCount = pSMB->TotalParameterCount;
5262 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005263 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264
5265 pSMB->DataCount = 0;
5266 pSMB->DataOffset = 0;
5267 pSMB->SetupCount = 1;
5268 pSMB->Reserved3 = 0;
5269 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5270 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005271 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 pSMB->ByteCount = cpu_to_le16(byte_count);
5273
5274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5275 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5276 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005277 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 } else { /* decode response */
5279 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5280
Jeff Layton820a8032011-05-04 08:05:26 -04005281 if (rc || get_bcc(&pSMBr->hdr) <
5282 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 rc = -EIO; /* bad smb */
5284 else {
5285 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5286 response_data =
Steve French737b7582005-04-28 22:41:06 -07005287 (FILE_SYSTEM_DEVICE_INFO *)
5288 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 data_offset);
5290 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005291 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 }
5293 }
5294 cifs_buf_release(pSMB);
5295
5296 if (rc == -EAGAIN)
5297 goto QFSDeviceRetry;
5298
5299 return rc;
5300}
5301
5302int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005303CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304{
5305/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5306 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5307 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5308 FILE_SYSTEM_UNIX_INFO *response_data;
5309 int rc = 0;
5310 int bytes_returned = 0;
5311 __u16 params, byte_count;
5312
Joe Perchesf96637b2013-05-04 22:12:25 -05005313 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005315 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5316 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 if (rc)
5318 return rc;
5319
5320 params = 2; /* level */
5321 pSMB->TotalDataCount = 0;
5322 pSMB->DataCount = 0;
5323 pSMB->DataOffset = 0;
5324 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005325 /* BB find exact max SMB PDU from sess structure BB */
5326 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 pSMB->MaxSetupCount = 0;
5328 pSMB->Reserved = 0;
5329 pSMB->Flags = 0;
5330 pSMB->Timeout = 0;
5331 pSMB->Reserved2 = 0;
5332 byte_count = params + 1 /* pad */ ;
5333 pSMB->ParameterCount = cpu_to_le16(params);
5334 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005335 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5336 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 pSMB->SetupCount = 1;
5338 pSMB->Reserved3 = 0;
5339 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5340 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005341 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 pSMB->ByteCount = cpu_to_le16(byte_count);
5343
5344 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5345 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5346 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005347 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 } else { /* decode response */
5349 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5350
Jeff Layton820a8032011-05-04 08:05:26 -04005351 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 rc = -EIO; /* bad smb */
5353 } else {
5354 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5355 response_data =
5356 (FILE_SYSTEM_UNIX_INFO
5357 *) (((char *) &pSMBr->hdr.Protocol) +
5358 data_offset);
5359 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005360 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 }
5362 }
5363 cifs_buf_release(pSMB);
5364
5365 if (rc == -EAGAIN)
5366 goto QFSUnixRetry;
5367
5368
5369 return rc;
5370}
5371
Jeremy Allisonac670552005-06-22 17:26:35 -07005372int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005373CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005374{
5375/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5376 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5377 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5378 int rc = 0;
5379 int bytes_returned = 0;
5380 __u16 params, param_offset, offset, byte_count;
5381
Joe Perchesf96637b2013-05-04 22:12:25 -05005382 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005383SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005384 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005385 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5386 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005387 if (rc)
5388 return rc;
5389
5390 params = 4; /* 2 bytes zero followed by info level. */
5391 pSMB->MaxSetupCount = 0;
5392 pSMB->Reserved = 0;
5393 pSMB->Flags = 0;
5394 pSMB->Timeout = 0;
5395 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005396 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5397 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005398 offset = param_offset + params;
5399
5400 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005401 /* BB find exact max SMB PDU from sess structure BB */
5402 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005403 pSMB->SetupCount = 1;
5404 pSMB->Reserved3 = 0;
5405 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5406 byte_count = 1 /* pad */ + params + 12;
5407
5408 pSMB->DataCount = cpu_to_le16(12);
5409 pSMB->ParameterCount = cpu_to_le16(params);
5410 pSMB->TotalDataCount = pSMB->DataCount;
5411 pSMB->TotalParameterCount = pSMB->ParameterCount;
5412 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5413 pSMB->DataOffset = cpu_to_le16(offset);
5414
5415 /* Params. */
5416 pSMB->FileNum = 0;
5417 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5418
5419 /* Data. */
5420 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5421 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5422 pSMB->ClientUnixCap = cpu_to_le64(cap);
5423
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005424 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005425 pSMB->ByteCount = cpu_to_le16(byte_count);
5426
5427 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5428 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5429 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005430 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005431 } else { /* decode response */
5432 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005433 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005434 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005435 }
5436 cifs_buf_release(pSMB);
5437
5438 if (rc == -EAGAIN)
5439 goto SETFSUnixRetry;
5440
5441 return rc;
5442}
5443
5444
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445
5446int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005447CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005448 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449{
5450/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5451 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5452 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5453 FILE_SYSTEM_POSIX_INFO *response_data;
5454 int rc = 0;
5455 int bytes_returned = 0;
5456 __u16 params, byte_count;
5457
Joe Perchesf96637b2013-05-04 22:12:25 -05005458 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459QFSPosixRetry:
5460 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5461 (void **) &pSMBr);
5462 if (rc)
5463 return rc;
5464
5465 params = 2; /* level */
5466 pSMB->TotalDataCount = 0;
5467 pSMB->DataCount = 0;
5468 pSMB->DataOffset = 0;
5469 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005470 /* BB find exact max SMB PDU from sess structure BB */
5471 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 pSMB->MaxSetupCount = 0;
5473 pSMB->Reserved = 0;
5474 pSMB->Flags = 0;
5475 pSMB->Timeout = 0;
5476 pSMB->Reserved2 = 0;
5477 byte_count = params + 1 /* pad */ ;
5478 pSMB->ParameterCount = cpu_to_le16(params);
5479 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005480 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5481 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 pSMB->SetupCount = 1;
5483 pSMB->Reserved3 = 0;
5484 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5485 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005486 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 pSMB->ByteCount = cpu_to_le16(byte_count);
5488
5489 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5490 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5491 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005492 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 } else { /* decode response */
5494 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5495
Jeff Layton820a8032011-05-04 08:05:26 -04005496 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 rc = -EIO; /* bad smb */
5498 } else {
5499 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5500 response_data =
5501 (FILE_SYSTEM_POSIX_INFO
5502 *) (((char *) &pSMBr->hdr.Protocol) +
5503 data_offset);
5504 FSData->f_bsize =
5505 le32_to_cpu(response_data->BlockSize);
5506 FSData->f_blocks =
5507 le64_to_cpu(response_data->TotalBlocks);
5508 FSData->f_bfree =
5509 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005510 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 FSData->f_bavail = FSData->f_bfree;
5512 } else {
5513 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005514 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 }
Steve French790fe572007-07-07 19:25:05 +00005516 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005518 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005519 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005521 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 }
5523 }
5524 cifs_buf_release(pSMB);
5525
5526 if (rc == -EAGAIN)
5527 goto QFSPosixRetry;
5528
5529 return rc;
5530}
5531
5532
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005533/*
5534 * We can not use write of zero bytes trick to set file size due to need for
5535 * large file support. Also note that this SetPathInfo is preferred to
5536 * SetFileInfo based method in next routine which is only needed to work around
5537 * a sharing violation bugin Samba which this routine can run into.
5538 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005540CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005541 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5542 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543{
5544 struct smb_com_transaction2_spi_req *pSMB = NULL;
5545 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5546 struct file_end_of_file_info *parm_data;
5547 int name_len;
5548 int rc = 0;
5549 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005550 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005551
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 __u16 params, byte_count, data_count, param_offset, offset;
5553
Joe Perchesf96637b2013-05-04 22:12:25 -05005554 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555SetEOFRetry:
5556 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5557 (void **) &pSMBr);
5558 if (rc)
5559 return rc;
5560
5561 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5562 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005563 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5564 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 name_len++; /* trailing null */
5566 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005567 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005568 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005570 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 }
5572 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005573 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005575 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 pSMB->MaxSetupCount = 0;
5577 pSMB->Reserved = 0;
5578 pSMB->Flags = 0;
5579 pSMB->Timeout = 0;
5580 pSMB->Reserved2 = 0;
5581 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005582 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005584 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005585 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5586 pSMB->InformationLevel =
5587 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5588 else
5589 pSMB->InformationLevel =
5590 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5591 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5593 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005594 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 else
5596 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005597 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 }
5599
5600 parm_data =
5601 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5602 offset);
5603 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5604 pSMB->DataOffset = cpu_to_le16(offset);
5605 pSMB->SetupCount = 1;
5606 pSMB->Reserved3 = 0;
5607 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5608 byte_count = 3 /* pad */ + params + data_count;
5609 pSMB->DataCount = cpu_to_le16(data_count);
5610 pSMB->TotalDataCount = pSMB->DataCount;
5611 pSMB->ParameterCount = cpu_to_le16(params);
5612 pSMB->TotalParameterCount = pSMB->ParameterCount;
5613 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005614 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 parm_data->FileSize = cpu_to_le64(size);
5616 pSMB->ByteCount = cpu_to_le16(byte_count);
5617 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5618 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005619 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005620 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621
5622 cifs_buf_release(pSMB);
5623
5624 if (rc == -EAGAIN)
5625 goto SetEOFRetry;
5626
5627 return rc;
5628}
5629
5630int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005631CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5632 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633{
5634 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 struct file_end_of_file_info *parm_data;
5636 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 __u16 params, param_offset, offset, byte_count, count;
5638
Joe Perchesf96637b2013-05-04 22:12:25 -05005639 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5640 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005641 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5642
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 if (rc)
5644 return rc;
5645
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005646 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5647 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005648
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 params = 6;
5650 pSMB->MaxSetupCount = 0;
5651 pSMB->Reserved = 0;
5652 pSMB->Flags = 0;
5653 pSMB->Timeout = 0;
5654 pSMB->Reserved2 = 0;
5655 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5656 offset = param_offset + params;
5657
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 count = sizeof(struct file_end_of_file_info);
5659 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005660 /* BB find exact max SMB PDU from sess structure BB */
5661 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 pSMB->SetupCount = 1;
5663 pSMB->Reserved3 = 0;
5664 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5665 byte_count = 3 /* pad */ + params + count;
5666 pSMB->DataCount = cpu_to_le16(count);
5667 pSMB->ParameterCount = cpu_to_le16(params);
5668 pSMB->TotalDataCount = pSMB->DataCount;
5669 pSMB->TotalParameterCount = pSMB->ParameterCount;
5670 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5671 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005672 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5673 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 pSMB->DataOffset = cpu_to_le16(offset);
5675 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005676 pSMB->Fid = cfile->fid.netfid;
5677 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5679 pSMB->InformationLevel =
5680 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5681 else
5682 pSMB->InformationLevel =
5683 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005684 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5686 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005687 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 else
5689 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005690 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 }
5692 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005693 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005695 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005696 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005698 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5699 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 }
5701
Steve French50c2f752007-07-13 00:33:32 +00005702 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 since file handle passed in no longer valid */
5704
5705 return rc;
5706}
5707
Steve French50c2f752007-07-13 00:33:32 +00005708/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 an open handle, rather than by pathname - this is awkward due to
5710 potential access conflicts on the open, but it is unavoidable for these
5711 old servers since the only other choice is to go from 100 nanosecond DCE
5712 time and resort to the original setpathinfo level which takes the ancient
5713 DOS time format with 2 second granularity */
5714int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005715CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005716 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717{
5718 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 char *data_offset;
5720 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 __u16 params, param_offset, offset, byte_count, count;
5722
Joe Perchesf96637b2013-05-04 22:12:25 -05005723 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005724 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5725
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 if (rc)
5727 return rc;
5728
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005729 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5730 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005731
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 params = 6;
5733 pSMB->MaxSetupCount = 0;
5734 pSMB->Reserved = 0;
5735 pSMB->Flags = 0;
5736 pSMB->Timeout = 0;
5737 pSMB->Reserved2 = 0;
5738 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5739 offset = param_offset + params;
5740
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005741 data_offset = (char *)pSMB +
5742 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743
Steve French26f57362007-08-30 22:09:15 +00005744 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005746 /* BB find max SMB PDU from sess */
5747 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 pSMB->SetupCount = 1;
5749 pSMB->Reserved3 = 0;
5750 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5751 byte_count = 3 /* pad */ + params + count;
5752 pSMB->DataCount = cpu_to_le16(count);
5753 pSMB->ParameterCount = cpu_to_le16(params);
5754 pSMB->TotalDataCount = pSMB->DataCount;
5755 pSMB->TotalParameterCount = pSMB->ParameterCount;
5756 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5757 pSMB->DataOffset = cpu_to_le16(offset);
5758 pSMB->Fid = fid;
5759 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5760 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5761 else
5762 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5763 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005764 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005766 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005767 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005768 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005769 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005770 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5771 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
Steve French50c2f752007-07-13 00:33:32 +00005773 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774 since file handle passed in no longer valid */
5775
5776 return rc;
5777}
5778
Jeff Layton6d22f092008-09-23 11:48:35 -04005779int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005780CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005781 bool delete_file, __u16 fid, __u32 pid_of_opener)
5782{
5783 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5784 char *data_offset;
5785 int rc = 0;
5786 __u16 params, param_offset, offset, byte_count, count;
5787
Joe Perchesf96637b2013-05-04 22:12:25 -05005788 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005789 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5790
5791 if (rc)
5792 return rc;
5793
5794 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5795 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5796
5797 params = 6;
5798 pSMB->MaxSetupCount = 0;
5799 pSMB->Reserved = 0;
5800 pSMB->Flags = 0;
5801 pSMB->Timeout = 0;
5802 pSMB->Reserved2 = 0;
5803 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5804 offset = param_offset + params;
5805
5806 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5807
5808 count = 1;
5809 pSMB->MaxParameterCount = cpu_to_le16(2);
5810 /* BB find max SMB PDU from sess */
5811 pSMB->MaxDataCount = cpu_to_le16(1000);
5812 pSMB->SetupCount = 1;
5813 pSMB->Reserved3 = 0;
5814 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5815 byte_count = 3 /* pad */ + params + count;
5816 pSMB->DataCount = cpu_to_le16(count);
5817 pSMB->ParameterCount = cpu_to_le16(params);
5818 pSMB->TotalDataCount = pSMB->DataCount;
5819 pSMB->TotalParameterCount = pSMB->ParameterCount;
5820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5821 pSMB->DataOffset = cpu_to_le16(offset);
5822 pSMB->Fid = fid;
5823 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5824 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005825 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005826 pSMB->ByteCount = cpu_to_le16(byte_count);
5827 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005828 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005829 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005830 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005831 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005832
5833 return rc;
5834}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835
5836int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005837CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005838 const char *fileName, const FILE_BASIC_INFO *data,
5839 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840{
5841 TRANSACTION2_SPI_REQ *pSMB = NULL;
5842 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5843 int name_len;
5844 int rc = 0;
5845 int bytes_returned = 0;
5846 char *data_offset;
5847 __u16 params, param_offset, offset, byte_count, count;
5848
Joe Perchesf96637b2013-05-04 22:12:25 -05005849 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850
5851SetTimesRetry:
5852 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5853 (void **) &pSMBr);
5854 if (rc)
5855 return rc;
5856
5857 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5858 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005859 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5860 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 name_len++; /* trailing null */
5862 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005863 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 name_len = strnlen(fileName, PATH_MAX);
5865 name_len++; /* trailing null */
5866 strncpy(pSMB->FileName, fileName, name_len);
5867 }
5868
5869 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005870 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005872 /* BB find max SMB PDU from sess structure BB */
5873 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874 pSMB->MaxSetupCount = 0;
5875 pSMB->Reserved = 0;
5876 pSMB->Flags = 0;
5877 pSMB->Timeout = 0;
5878 pSMB->Reserved2 = 0;
5879 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005880 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 offset = param_offset + params;
5882 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5883 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5884 pSMB->DataOffset = cpu_to_le16(offset);
5885 pSMB->SetupCount = 1;
5886 pSMB->Reserved3 = 0;
5887 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5888 byte_count = 3 /* pad */ + params + count;
5889
5890 pSMB->DataCount = cpu_to_le16(count);
5891 pSMB->ParameterCount = cpu_to_le16(params);
5892 pSMB->TotalDataCount = pSMB->DataCount;
5893 pSMB->TotalParameterCount = pSMB->ParameterCount;
5894 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5895 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5896 else
5897 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5898 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005899 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005900 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 pSMB->ByteCount = cpu_to_le16(byte_count);
5902 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5903 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005904 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005905 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906
5907 cifs_buf_release(pSMB);
5908
5909 if (rc == -EAGAIN)
5910 goto SetTimesRetry;
5911
5912 return rc;
5913}
5914
5915/* Can not be used to set time stamps yet (due to old DOS time format) */
5916/* Can be used to set attributes */
5917#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5918 handling it anyway and NT4 was what we thought it would be needed for
5919 Do not delete it until we prove whether needed for Win9x though */
5920int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005921CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 __u16 dos_attrs, const struct nls_table *nls_codepage)
5923{
5924 SETATTR_REQ *pSMB = NULL;
5925 SETATTR_RSP *pSMBr = NULL;
5926 int rc = 0;
5927 int bytes_returned;
5928 int name_len;
5929
Joe Perchesf96637b2013-05-04 22:12:25 -05005930 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931
5932SetAttrLgcyRetry:
5933 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5934 (void **) &pSMBr);
5935 if (rc)
5936 return rc;
5937
5938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5939 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005940 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5941 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942 name_len++; /* trailing null */
5943 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005944 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945 name_len = strnlen(fileName, PATH_MAX);
5946 name_len++; /* trailing null */
5947 strncpy(pSMB->fileName, fileName, name_len);
5948 }
5949 pSMB->attr = cpu_to_le16(dos_attrs);
5950 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005951 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005955 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005956 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957
5958 cifs_buf_release(pSMB);
5959
5960 if (rc == -EAGAIN)
5961 goto SetAttrLgcyRetry;
5962
5963 return rc;
5964}
5965#endif /* temporarily unneeded SetAttr legacy function */
5966
Jeff Layton654cf142009-07-09 20:02:49 -04005967static void
5968cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5969 const struct cifs_unix_set_info_args *args)
5970{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005971 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005972 u64 mode = args->mode;
5973
Eric W. Biederman49418b22013-02-06 00:57:56 -08005974 if (uid_valid(args->uid))
5975 uid = from_kuid(&init_user_ns, args->uid);
5976 if (gid_valid(args->gid))
5977 gid = from_kgid(&init_user_ns, args->gid);
5978
Jeff Layton654cf142009-07-09 20:02:49 -04005979 /*
5980 * Samba server ignores set of file size to zero due to bugs in some
5981 * older clients, but we should be precise - we use SetFileSize to
5982 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005983 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005984 * zero instead of -1 here
5985 */
5986 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5987 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5988 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5989 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5990 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005991 data_offset->Uid = cpu_to_le64(uid);
5992 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005993 /* better to leave device as zero when it is */
5994 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5995 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5996 data_offset->Permissions = cpu_to_le64(mode);
5997
5998 if (S_ISREG(mode))
5999 data_offset->Type = cpu_to_le32(UNIX_FILE);
6000 else if (S_ISDIR(mode))
6001 data_offset->Type = cpu_to_le32(UNIX_DIR);
6002 else if (S_ISLNK(mode))
6003 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6004 else if (S_ISCHR(mode))
6005 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6006 else if (S_ISBLK(mode))
6007 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6008 else if (S_ISFIFO(mode))
6009 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6010 else if (S_ISSOCK(mode))
6011 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6012}
6013
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006015CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006016 const struct cifs_unix_set_info_args *args,
6017 u16 fid, u32 pid_of_opener)
6018{
6019 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006020 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006021 int rc = 0;
6022 u16 params, param_offset, offset, byte_count, count;
6023
Joe Perchesf96637b2013-05-04 22:12:25 -05006024 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006025 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6026
6027 if (rc)
6028 return rc;
6029
6030 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6031 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6032
6033 params = 6;
6034 pSMB->MaxSetupCount = 0;
6035 pSMB->Reserved = 0;
6036 pSMB->Flags = 0;
6037 pSMB->Timeout = 0;
6038 pSMB->Reserved2 = 0;
6039 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6040 offset = param_offset + params;
6041
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006042 data_offset = (char *)pSMB +
6043 offsetof(struct smb_hdr, Protocol) + offset;
6044
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006045 count = sizeof(FILE_UNIX_BASIC_INFO);
6046
6047 pSMB->MaxParameterCount = cpu_to_le16(2);
6048 /* BB find max SMB PDU from sess */
6049 pSMB->MaxDataCount = cpu_to_le16(1000);
6050 pSMB->SetupCount = 1;
6051 pSMB->Reserved3 = 0;
6052 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6053 byte_count = 3 /* pad */ + params + count;
6054 pSMB->DataCount = cpu_to_le16(count);
6055 pSMB->ParameterCount = cpu_to_le16(params);
6056 pSMB->TotalDataCount = pSMB->DataCount;
6057 pSMB->TotalParameterCount = pSMB->ParameterCount;
6058 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6059 pSMB->DataOffset = cpu_to_le16(offset);
6060 pSMB->Fid = fid;
6061 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6062 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006063 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006064 pSMB->ByteCount = cpu_to_le16(byte_count);
6065
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006066 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006067
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006068 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006069 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006070 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006071 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6072 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006073
6074 /* Note: On -EAGAIN error only caller can retry on handle based calls
6075 since file handle passed in no longer valid */
6076
6077 return rc;
6078}
6079
6080int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006081CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006082 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006083 const struct cifs_unix_set_info_args *args,
6084 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085{
6086 TRANSACTION2_SPI_REQ *pSMB = NULL;
6087 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6088 int name_len;
6089 int rc = 0;
6090 int bytes_returned = 0;
6091 FILE_UNIX_BASIC_INFO *data_offset;
6092 __u16 params, param_offset, offset, count, byte_count;
6093
Joe Perchesf96637b2013-05-04 22:12:25 -05006094 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095setPermsRetry:
6096 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6097 (void **) &pSMBr);
6098 if (rc)
6099 return rc;
6100
6101 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6102 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006103 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006104 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 name_len++; /* trailing null */
6106 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006107 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006108 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006110 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111 }
6112
6113 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006114 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006116 /* BB find max SMB PDU from sess structure BB */
6117 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 pSMB->MaxSetupCount = 0;
6119 pSMB->Reserved = 0;
6120 pSMB->Flags = 0;
6121 pSMB->Timeout = 0;
6122 pSMB->Reserved2 = 0;
6123 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006124 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 offset = param_offset + params;
6126 data_offset =
6127 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6128 offset);
6129 memset(data_offset, 0, count);
6130 pSMB->DataOffset = cpu_to_le16(offset);
6131 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6132 pSMB->SetupCount = 1;
6133 pSMB->Reserved3 = 0;
6134 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6135 byte_count = 3 /* pad */ + params + count;
6136 pSMB->ParameterCount = cpu_to_le16(params);
6137 pSMB->DataCount = cpu_to_le16(count);
6138 pSMB->TotalParameterCount = pSMB->ParameterCount;
6139 pSMB->TotalDataCount = pSMB->DataCount;
6140 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6141 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006142 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006143
Jeff Layton654cf142009-07-09 20:02:49 -04006144 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145
6146 pSMB->ByteCount = cpu_to_le16(byte_count);
6147 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6148 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006149 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006150 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151
Steve French0d817bc2008-05-22 02:02:03 +00006152 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 if (rc == -EAGAIN)
6154 goto setPermsRetry;
6155 return rc;
6156}
6157
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006159/*
6160 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6161 * function used by listxattr and getxattr type calls. When ea_name is set,
6162 * it looks for that attribute name and stuffs that value into the EAData
6163 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6164 * buffer. In both cases, the return value is either the length of the
6165 * resulting data or a negative error code. If EAData is a NULL pointer then
6166 * the data isn't copied to it, but the length is returned.
6167 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006169CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006170 const unsigned char *searchName, const unsigned char *ea_name,
6171 char *EAData, size_t buf_size,
6172 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173{
6174 /* BB assumes one setup word */
6175 TRANSACTION2_QPI_REQ *pSMB = NULL;
6176 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6177 int rc = 0;
6178 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006179 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006181 struct fea *temp_fea;
6182 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006183 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006184 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006185 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186
Joe Perchesf96637b2013-05-04 22:12:25 -05006187 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188QAllEAsRetry:
6189 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6190 (void **) &pSMBr);
6191 if (rc)
6192 return rc;
6193
6194 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006195 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006196 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6197 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006198 list_len++; /* trailing null */
6199 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006201 list_len = strnlen(searchName, PATH_MAX);
6202 list_len++; /* trailing null */
6203 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204 }
6205
Jeff Layton6e462b92010-02-10 16:18:26 -05006206 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207 pSMB->TotalDataCount = 0;
6208 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006209 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006210 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 pSMB->MaxSetupCount = 0;
6212 pSMB->Reserved = 0;
6213 pSMB->Flags = 0;
6214 pSMB->Timeout = 0;
6215 pSMB->Reserved2 = 0;
6216 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006217 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218 pSMB->DataCount = 0;
6219 pSMB->DataOffset = 0;
6220 pSMB->SetupCount = 1;
6221 pSMB->Reserved3 = 0;
6222 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6223 byte_count = params + 1 /* pad */ ;
6224 pSMB->TotalParameterCount = cpu_to_le16(params);
6225 pSMB->ParameterCount = pSMB->TotalParameterCount;
6226 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6227 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006228 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 pSMB->ByteCount = cpu_to_le16(byte_count);
6230
6231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6233 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006234 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006235 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006237
6238
6239 /* BB also check enough total bytes returned */
6240 /* BB we need to improve the validity checking
6241 of these trans2 responses */
6242
6243 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006244 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006245 rc = -EIO; /* bad smb */
6246 goto QAllEAsOut;
6247 }
6248
6249 /* check that length of list is not more than bcc */
6250 /* check that each entry does not go beyond length
6251 of list */
6252 /* check that each element of each entry does not
6253 go beyond end of list */
6254 /* validate_trans2_offsets() */
6255 /* BB check if start of smb + data_offset > &bcc+ bcc */
6256
6257 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6258 ea_response_data = (struct fealist *)
6259 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6260
Jeff Layton6e462b92010-02-10 16:18:26 -05006261 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006262 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006263 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006264 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006265 /* didn't find the named attribute */
6266 if (ea_name)
6267 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006268 goto QAllEAsOut;
6269 }
6270
Jeff Layton0cd126b2010-02-10 16:18:26 -05006271 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006272 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006273 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006274 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006275 rc = -EIO;
6276 goto QAllEAsOut;
6277 }
6278
Jeff Laytonf0d38682010-02-10 16:18:26 -05006279 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006280 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006281 temp_fea = ea_response_data->list;
6282 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006283 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006284 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006285 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006286
Jeff Layton6e462b92010-02-10 16:18:26 -05006287 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006288 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006289 /* make sure we can read name_len and value_len */
6290 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006291 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006292 rc = -EIO;
6293 goto QAllEAsOut;
6294 }
6295
6296 name_len = temp_fea->name_len;
6297 value_len = le16_to_cpu(temp_fea->value_len);
6298 list_len -= name_len + 1 + value_len;
6299 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006300 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006301 rc = -EIO;
6302 goto QAllEAsOut;
6303 }
6304
Jeff Layton31c05192010-02-10 16:18:26 -05006305 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006306 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006307 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006308 temp_ptr += name_len + 1;
6309 rc = value_len;
6310 if (buf_size == 0)
6311 goto QAllEAsOut;
6312 if ((size_t)value_len > buf_size) {
6313 rc = -ERANGE;
6314 goto QAllEAsOut;
6315 }
6316 memcpy(EAData, temp_ptr, value_len);
6317 goto QAllEAsOut;
6318 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006319 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006320 /* account for prefix user. and trailing null */
6321 rc += (5 + 1 + name_len);
6322 if (rc < (int) buf_size) {
6323 memcpy(EAData, "user.", 5);
6324 EAData += 5;
6325 memcpy(EAData, temp_ptr, name_len);
6326 EAData += name_len;
6327 /* null terminate name */
6328 *EAData = 0;
6329 ++EAData;
6330 } else if (buf_size == 0) {
6331 /* skip copy - calc size only */
6332 } else {
6333 /* stop before overrun buffer */
6334 rc = -ERANGE;
6335 break;
6336 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006337 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006338 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006339 temp_fea = (struct fea *)temp_ptr;
6340 }
6341
Jeff Layton31c05192010-02-10 16:18:26 -05006342 /* didn't find the named attribute */
6343 if (ea_name)
6344 rc = -ENODATA;
6345
Jeff Laytonf0d38682010-02-10 16:18:26 -05006346QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006347 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 if (rc == -EAGAIN)
6349 goto QAllEAsRetry;
6350
6351 return (ssize_t)rc;
6352}
6353
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006355CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6356 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006357 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6358 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359{
6360 struct smb_com_transaction2_spi_req *pSMB = NULL;
6361 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6362 struct fealist *parm_data;
6363 int name_len;
6364 int rc = 0;
6365 int bytes_returned = 0;
6366 __u16 params, param_offset, byte_count, offset, count;
6367
Joe Perchesf96637b2013-05-04 22:12:25 -05006368 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369SetEARetry:
6370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6371 (void **) &pSMBr);
6372 if (rc)
6373 return rc;
6374
6375 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6376 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006377 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6378 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 name_len++; /* trailing null */
6380 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006381 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 name_len = strnlen(fileName, PATH_MAX);
6383 name_len++; /* trailing null */
6384 strncpy(pSMB->FileName, fileName, name_len);
6385 }
6386
6387 params = 6 + name_len;
6388
6389 /* done calculating parms using name_len of file name,
6390 now use name_len to calculate length of ea name
6391 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006392 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 name_len = 0;
6394 else
Steve French50c2f752007-07-13 00:33:32 +00006395 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006396
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006397 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006399 /* BB find max SMB PDU from sess */
6400 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401 pSMB->MaxSetupCount = 0;
6402 pSMB->Reserved = 0;
6403 pSMB->Flags = 0;
6404 pSMB->Timeout = 0;
6405 pSMB->Reserved2 = 0;
6406 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006407 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 offset = param_offset + params;
6409 pSMB->InformationLevel =
6410 cpu_to_le16(SMB_SET_FILE_EA);
6411
6412 parm_data =
6413 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6414 offset);
6415 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6416 pSMB->DataOffset = cpu_to_le16(offset);
6417 pSMB->SetupCount = 1;
6418 pSMB->Reserved3 = 0;
6419 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6420 byte_count = 3 /* pad */ + params + count;
6421 pSMB->DataCount = cpu_to_le16(count);
6422 parm_data->list_len = cpu_to_le32(count);
6423 parm_data->list[0].EA_flags = 0;
6424 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006425 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006427 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006428 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429 parm_data->list[0].name[name_len] = 0;
6430 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6431 /* caller ensures that ea_value_len is less than 64K but
6432 we need to ensure that it fits within the smb */
6433
Steve French50c2f752007-07-13 00:33:32 +00006434 /*BB add length check to see if it would fit in
6435 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006436 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6437 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006438 memcpy(parm_data->list[0].name+name_len+1,
6439 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440
6441 pSMB->TotalDataCount = pSMB->DataCount;
6442 pSMB->ParameterCount = cpu_to_le16(params);
6443 pSMB->TotalParameterCount = pSMB->ParameterCount;
6444 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006445 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446 pSMB->ByteCount = cpu_to_le16(byte_count);
6447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006449 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006450 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451
6452 cifs_buf_release(pSMB);
6453
6454 if (rc == -EAGAIN)
6455 goto SetEARetry;
6456
6457 return rc;
6458}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459#endif
Steve French0eff0e22011-02-24 05:39:23 +00006460
6461#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6462/*
6463 * Years ago the kernel added a "dnotify" function for Samba server,
6464 * to allow network clients (such as Windows) to display updated
6465 * lists of files in directory listings automatically when
6466 * files are added by one user when another user has the
6467 * same directory open on their desktop. The Linux cifs kernel
6468 * client hooked into the kernel side of this interface for
6469 * the same reason, but ironically when the VFS moved from
6470 * "dnotify" to "inotify" it became harder to plug in Linux
6471 * network file system clients (the most obvious use case
6472 * for notify interfaces is when multiple users can update
6473 * the contents of the same directory - exactly what network
6474 * file systems can do) although the server (Samba) could
6475 * still use it. For the short term we leave the worker
6476 * function ifdeffed out (below) until inotify is fixed
6477 * in the VFS to make it easier to plug in network file
6478 * system clients. If inotify turns out to be permanently
6479 * incompatible for network fs clients, we could instead simply
6480 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6481 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006482int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006483 const int notify_subdirs, const __u16 netfid,
6484 __u32 filter, struct file *pfile, int multishot,
6485 const struct nls_table *nls_codepage)
6486{
6487 int rc = 0;
6488 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6489 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6490 struct dir_notify_req *dnotify_req;
6491 int bytes_returned;
6492
Joe Perchesf96637b2013-05-04 22:12:25 -05006493 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006494 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6495 (void **) &pSMBr);
6496 if (rc)
6497 return rc;
6498
6499 pSMB->TotalParameterCount = 0 ;
6500 pSMB->TotalDataCount = 0;
6501 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006502 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006503 pSMB->MaxSetupCount = 4;
6504 pSMB->Reserved = 0;
6505 pSMB->ParameterOffset = 0;
6506 pSMB->DataCount = 0;
6507 pSMB->DataOffset = 0;
6508 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6509 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6510 pSMB->ParameterCount = pSMB->TotalParameterCount;
6511 if (notify_subdirs)
6512 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6513 pSMB->Reserved2 = 0;
6514 pSMB->CompletionFilter = cpu_to_le32(filter);
6515 pSMB->Fid = netfid; /* file handle always le */
6516 pSMB->ByteCount = 0;
6517
6518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6519 (struct smb_hdr *)pSMBr, &bytes_returned,
6520 CIFS_ASYNC_OP);
6521 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006522 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006523 } else {
6524 /* Add file to outstanding requests */
6525 /* BB change to kmem cache alloc */
6526 dnotify_req = kmalloc(
6527 sizeof(struct dir_notify_req),
6528 GFP_KERNEL);
6529 if (dnotify_req) {
6530 dnotify_req->Pid = pSMB->hdr.Pid;
6531 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6532 dnotify_req->Mid = pSMB->hdr.Mid;
6533 dnotify_req->Tid = pSMB->hdr.Tid;
6534 dnotify_req->Uid = pSMB->hdr.Uid;
6535 dnotify_req->netfid = netfid;
6536 dnotify_req->pfile = pfile;
6537 dnotify_req->filter = filter;
6538 dnotify_req->multishot = multishot;
6539 spin_lock(&GlobalMid_Lock);
6540 list_add_tail(&dnotify_req->lhead,
6541 &GlobalDnotifyReqList);
6542 spin_unlock(&GlobalMid_Lock);
6543 } else
6544 rc = -ENOMEM;
6545 }
6546 cifs_buf_release(pSMB);
6547 return rc;
6548}
6549#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */