blob: abdc93d4fee82c0509b5783d4d8ecca08095891b [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"
Long Lidb223a52017-11-22 17:38:45 -070046#include "smbdirect.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#ifdef CONFIG_CIFS_POSIX
49static struct {
50 int index;
51 char *name;
52} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000053#ifdef CONFIG_CIFS_WEAK_PW_HASH
54 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000055 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000056#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000057 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000058 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 {BAD_PROT, "\2"}
60};
61#else
62static struct {
63 int index;
64 char *name;
65} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000066#ifdef CONFIG_CIFS_WEAK_PW_HASH
67 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000068 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000069#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000070 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 {BAD_PROT, "\2"}
72};
73#endif
74
Steve French39798772006-05-31 22:40:51 +000075/* define the number of elements in the cifs dialect array */
76#ifdef CONFIG_CIFS_POSIX
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 2
81#endif /* CIFS_WEAK_PW_HASH */
82#else /* not posix */
83#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000084#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000085#else
86#define CIFS_NUM_PROT 1
87#endif /* CONFIG_CIFS_WEAK_PW_HASH */
88#endif /* CIFS_POSIX */
89
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040090/*
91 * Mark as invalid, all open files on tree connections since they
92 * were closed when session to server was lost.
93 */
94void
95cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
97 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000098 struct list_head *tmp;
99 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400101 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500102 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400103 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000104 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000105 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400106 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 }
Steve French3afca262016-09-22 18:58:16 -0500108 spin_unlock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400109 /*
110 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
111 * to this tcon.
112 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113}
114
Jeff Layton9162ab22009-09-03 12:07:17 -0400115/* reconnect the socket, tcon, and smb session if needed */
116static int
Steve French96daf2b2011-05-27 04:34:02 +0000117cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400118{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400119 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000120 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400121 struct TCP_Server_Info *server;
122 struct nls_table *nls_codepage;
123
124 /*
125 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
126 * tcp and smb session status done differently for those three - in the
127 * calling routine
128 */
129 if (!tcon)
130 return 0;
131
132 ses = tcon->ses;
133 server = ses->server;
134
135 /*
136 * only tree disconnect, open, and write, (and ulogoff which does not
137 * have tcon) are allowed as we start force umount
138 */
139 if (tcon->tidStatus == CifsExiting) {
140 if (smb_command != SMB_COM_WRITE_ANDX &&
141 smb_command != SMB_COM_OPEN_ANDX &&
142 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500143 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
144 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400145 return -ENODEV;
146 }
147 }
148
Jeff Layton9162ab22009-09-03 12:07:17 -0400149 /*
150 * Give demultiplex thread up to 10 seconds to reconnect, should be
151 * greater than cifs socket timeout which is 7 seconds
152 */
153 while (server->tcpStatus == CifsNeedReconnect) {
154 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000155 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400156
Steve Frenchfd88ce92011-04-12 01:01:14 +0000157 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400158 if (server->tcpStatus != CifsNeedReconnect)
159 break;
160
161 /*
162 * on "soft" mounts we wait once. Hard mounts keep
163 * retrying until process is killed or server comes
164 * back on-line
165 */
Jeff Laytond4025392011-02-07 08:54:35 -0500166 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500167 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400168 return -EHOSTDOWN;
169 }
170 }
171
172 if (!ses->need_reconnect && !tcon->need_reconnect)
173 return 0;
174
175 nls_codepage = load_nls_default();
176
177 /*
178 * need to prevent multiple threads trying to simultaneously
179 * reconnect the same SMB session
180 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000181 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200182
183 /*
184 * Recheck after acquire mutex. If another thread is negotiating
185 * and the server never sends an answer the socket will be closed
186 * and tcpStatus set to reconnect.
187 */
188 if (server->tcpStatus == CifsNeedReconnect) {
189 rc = -EHOSTDOWN;
190 mutex_unlock(&ses->session_mutex);
191 goto out;
192 }
193
Jeff Layton198b5682010-04-24 07:57:48 -0400194 rc = cifs_negotiate_protocol(0, ses);
195 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400196 rc = cifs_setup_session(0, ses, nls_codepage);
197
198 /* do we need to reconnect tcon? */
199 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000200 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400201 goto out;
202 }
203
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400204 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400205 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000206 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500207 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400208
Steve Frenchc318e6c2018-04-04 14:08:52 -0500209 if (rc) {
210 printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400211 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500212 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400213
Jeff Layton9162ab22009-09-03 12:07:17 -0400214 atomic_inc(&tconInfoReconnectCount);
215
216 /* tell server Unix caps we support */
217 if (ses->capabilities & CAP_UNIX)
218 reset_cifs_unix_caps(0, tcon, NULL, NULL);
219
220 /*
221 * Removed call to reopen open files here. It is safer (and faster) to
222 * reopen files one at a time as needed in read and write.
223 *
224 * FIXME: what about file locks? don't we need to reclaim them ASAP?
225 */
226
227out:
228 /*
229 * Check if handle based operation so we know whether we can continue
230 * or not without returning to caller to reset file handle
231 */
232 switch (smb_command) {
233 case SMB_COM_READ_ANDX:
234 case SMB_COM_WRITE_ANDX:
235 case SMB_COM_CLOSE:
236 case SMB_COM_FIND_CLOSE2:
237 case SMB_COM_LOCKING_ANDX:
238 rc = -EAGAIN;
239 }
240
241 unload_nls(nls_codepage);
242 return rc;
243}
244
Steve Frenchad7a2922008-02-07 23:25:02 +0000245/* Allocate and return pointer to an SMB request buffer, and set basic
246 SMB information in the SMB header. If the return code is zero, this
247 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248static int
Steve French96daf2b2011-05-27 04:34:02 +0000249small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000250 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
Jeff Laytonf5695992010-09-29 15:27:08 -0400252 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Jeff Layton9162ab22009-09-03 12:07:17 -0400254 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000255 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return rc;
257
258 *request_buf = cifs_small_buf_get();
259 if (*request_buf == NULL) {
260 /* BB should we add a retry in here if not a writepage? */
261 return -ENOMEM;
262 }
263
Steve French63135e02007-07-17 17:34:02 +0000264 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000265 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Steve French790fe572007-07-07 19:25:05 +0000267 if (tcon != NULL)
268 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700269
Jeff Laytonf5695992010-09-29 15:27:08 -0400270 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000271}
272
Steve French12b3b8f2006-02-09 21:12:47 +0000273int
Steve French50c2f752007-07-13 00:33:32 +0000274small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000275 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000276{
277 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000278 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000279
Steve French5815449d2006-02-14 01:36:20 +0000280 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000281 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000282 return rc;
283
Steve French04fdabe2006-02-10 05:52:50 +0000284 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400285 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000286 if (ses->capabilities & CAP_UNICODE)
287 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000288 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000289 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
290
291 /* uid, tid can stay at zero as set in header assemble */
292
Steve French50c2f752007-07-13 00:33:32 +0000293 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000294 this function is used after 1st of session setup requests */
295
296 return rc;
297}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299/* If the return code is zero, this function must fill in request_buf pointer */
300static int
Steve French96daf2b2011-05-27 04:34:02 +0000301__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400302 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 *request_buf = cifs_buf_get();
305 if (*request_buf == NULL) {
306 /* BB should we add a retry in here if not a writepage? */
307 return -ENOMEM;
308 }
309 /* Although the original thought was we needed the response buf for */
310 /* potential retries of smb operations it turns out we can determine */
311 /* from the mid flags when the request buffer can be resent without */
312 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000313 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000314 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000317 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Steve French790fe572007-07-07 19:25:05 +0000319 if (tcon != NULL)
320 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700321
Jeff Laytonf5695992010-09-29 15:27:08 -0400322 return 0;
323}
324
325/* If the return code is zero, this function must fill in request_buf pointer */
326static int
Steve French96daf2b2011-05-27 04:34:02 +0000327smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400328 void **request_buf, void **response_buf)
329{
330 int rc;
331
332 rc = cifs_reconnect_tcon(tcon, smb_command);
333 if (rc)
334 return rc;
335
336 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
337}
338
339static int
Steve French96daf2b2011-05-27 04:34:02 +0000340smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400341 void **request_buf, void **response_buf)
342{
343 if (tcon->ses->need_reconnect || tcon->need_reconnect)
344 return -EHOSTDOWN;
345
346 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Steve French50c2f752007-07-13 00:33:32 +0000349static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Jeff Layton12df83c2011-01-20 13:36:51 -0500353 /* check for plausible wct */
354 if (pSMB->hdr.WordCount < 10)
355 goto vt2_err;
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
359 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
360 goto vt2_err;
361
Jeff Layton12df83c2011-01-20 13:36:51 -0500362 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
363 if (total_size >= 512)
364 goto vt2_err;
365
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400366 /* check that bcc is at least as big as parms + data, and that it is
367 * less than negotiated smb buffer
368 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500369 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
370 if (total_size > get_bcc(&pSMB->hdr) ||
371 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
372 goto vt2_err;
373
374 return 0;
375vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000376 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500378 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379}
Jeff Layton690c5222011-01-20 13:36:51 -0500380
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400381static int
Jeff Layton3f618222013-06-12 19:52:14 -0500382decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400383{
384 int rc = 0;
385 u16 count;
386 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500387 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400388
389 count = get_bcc(&pSMBr->hdr);
390 if (count < SMB1_CLIENT_GUID_SIZE)
391 return -EIO;
392
393 spin_lock(&cifs_tcp_ses_lock);
394 if (server->srv_count > 1) {
395 spin_unlock(&cifs_tcp_ses_lock);
396 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
397 cifs_dbg(FYI, "server UID changed\n");
398 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
399 }
400 } else {
401 spin_unlock(&cifs_tcp_ses_lock);
402 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
403 }
404
405 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500406 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400407 } else {
408 count -= SMB1_CLIENT_GUID_SIZE;
409 rc = decode_negTokenInit(
410 pSMBr->u.extended_response.SecurityBlob, count, server);
411 if (rc != 1)
412 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400413 }
414
415 return 0;
416}
417
Jeff Layton9ddec562013-05-26 07:00:58 -0400418int
Jeff Layton38d77c52013-05-26 07:01:00 -0400419cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400420{
Jeff Layton502858822013-06-27 12:45:00 -0400421 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
422 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400423 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
424
425 /*
426 * Is signing required by mnt options? If not then check
427 * global_secflags to see if it is there.
428 */
429 if (!mnt_sign_required)
430 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
431 CIFSSEC_MUST_SIGN);
432
433 /*
434 * If signing is required then it's automatically enabled too,
435 * otherwise, check to see if the secflags allow it.
436 */
437 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
438 (global_secflags & CIFSSEC_MAY_SIGN);
439
440 /* If server requires signing, does client allow it? */
441 if (srv_sign_required) {
442 if (!mnt_sign_enabled) {
443 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
444 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400445 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400446 server->sign = true;
447 }
448
449 /* If client requires signing, does server allow it? */
450 if (mnt_sign_required) {
451 if (!srv_sign_enabled) {
452 cifs_dbg(VFS, "Server does not support signing!");
453 return -ENOTSUPP;
454 }
455 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400456 }
457
458 return 0;
459}
460
Jeff Layton2190eca2013-05-26 07:00:57 -0400461#ifdef CONFIG_CIFS_WEAK_PW_HASH
462static int
Jeff Layton3f618222013-06-12 19:52:14 -0500463decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400464{
465 __s16 tmp;
466 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
467
468 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
469 return -EOPNOTSUPP;
470
Jeff Layton2190eca2013-05-26 07:00:57 -0400471 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
472 server->maxReq = min_t(unsigned int,
473 le16_to_cpu(rsp->MaxMpxCount),
474 cifs_max_pending);
475 set_credits(server, server->maxReq);
476 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400477 /* even though we do not use raw we might as well set this
478 accurately, in case we ever find a need for it */
479 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
480 server->max_rw = 0xFF00;
481 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
482 } else {
483 server->max_rw = 0;/* do not need to use raw anyway */
484 server->capabilities = CAP_MPX_MODE;
485 }
486 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
487 if (tmp == -1) {
488 /* OS/2 often does not set timezone therefore
489 * we must use server time to calc time zone.
490 * Could deviate slightly from the right zone.
491 * Smallest defined timezone difference is 15 minutes
492 * (i.e. Nepal). Rounding up/down is done to match
493 * this requirement.
494 */
495 int val, seconds, remain, result;
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700496 struct timespec ts;
497 unsigned long utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400498 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
499 rsp->SrvTime.Time, 0);
500 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700501 (int)ts.tv_sec, (int)utc,
502 (int)(utc - ts.tv_sec));
503 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400504 seconds = abs(val);
505 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
506 remain = seconds % MIN_TZ_ADJ;
507 if (remain >= (MIN_TZ_ADJ / 2))
508 result += MIN_TZ_ADJ;
509 if (val < 0)
510 result = -result;
511 server->timeAdj = result;
512 } else {
513 server->timeAdj = (int)tmp;
514 server->timeAdj *= 60; /* also in seconds */
515 }
516 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
517
518
519 /* BB get server time for time conversions and add
520 code to use it and timezone since this is not UTC */
521
522 if (rsp->EncryptionKeyLength ==
523 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
524 memcpy(server->cryptkey, rsp->EncryptionKey,
525 CIFS_CRYPTO_KEY_SIZE);
526 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
527 return -EIO; /* need cryptkey unless plain text */
528 }
529
530 cifs_dbg(FYI, "LANMAN negotiated\n");
531 return 0;
532}
533#else
534static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500535decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400536{
537 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
538 return -EOPNOTSUPP;
539}
540#endif
541
Jeff Layton91934002013-05-26 07:00:58 -0400542static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500543should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400544{
Jeff Layton3f618222013-06-12 19:52:14 -0500545 switch (sectype) {
546 case RawNTLMSSP:
547 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400548 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500549 case Unspecified:
550 if (global_secflags &
551 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
552 return true;
553 /* Fallthrough */
554 default:
555 return false;
556 }
Jeff Layton91934002013-05-26 07:00:58 -0400557}
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400560CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
562 NEGOTIATE_REQ *pSMB;
563 NEGOTIATE_RSP *pSMBr;
564 int rc = 0;
565 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000566 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400567 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 u16 count;
569
Jeff Layton3534b852013-05-24 07:41:01 -0400570 if (!server) {
571 WARN(1, "%s: server is NULL!\n", __func__);
572 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 }
Jeff Layton3534b852013-05-24 07:41:01 -0400574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
576 (void **) &pSMB, (void **) &pSMBr);
577 if (rc)
578 return rc;
Steve French750d1152006-06-27 06:28:30 +0000579
Pavel Shilovsky88257362012-05-23 14:01:59 +0400580 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000581 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000582
Jeff Layton3f618222013-06-12 19:52:14 -0500583 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400584 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000585 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
586 }
Steve French50c2f752007-07-13 00:33:32 +0000587
Steve French39798772006-05-31 22:40:51 +0000588 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000589 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000590 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
591 count += strlen(protocols[i].name) + 1;
592 /* null at end of source and target buffers anyway */
593 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000594 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 pSMB->ByteCount = cpu_to_le16(count);
596
597 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
598 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000599 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000600 goto neg_err_exit;
601
Jeff Layton9bf67e52010-04-24 07:57:46 -0400602 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500603 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000604 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400605 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000606 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000607 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000608 could not negotiate a common dialect */
609 rc = -EOPNOTSUPP;
610 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000611 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400612 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500613 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400614 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000615 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000616 /* unknown wct */
617 rc = -EOPNOTSUPP;
618 goto neg_err_exit;
619 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400620 /* else wct == 17, NTLM or better */
621
Steve French96daf2b2011-05-27 04:34:02 +0000622 server->sec_mode = pSMBr->SecurityMode;
623 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500624 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000625
Steve French254e55e2006-06-04 05:53:15 +0000626 /* one byte, so no need to convert this or EncryptionKeyLen from
627 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300628 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
629 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400630 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000631 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400632 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000633 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500634 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000635 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000636 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
637 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400638
Jeff Laytone598d1d82013-05-26 07:00:59 -0400639 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
640 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500641 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000642 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100643 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
644 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400645 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500646 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400647 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000648 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400649 } else {
650 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000651 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400652 }
Steve French254e55e2006-06-04 05:53:15 +0000653
654signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400655 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400656 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000657neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700658 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000659
Joe Perchesf96637b2013-05-04 22:12:25 -0500660 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return rc;
662}
663
664int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400665CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
667 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Joe Perchesf96637b2013-05-04 22:12:25 -0500670 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500671
672 /* BB: do we need to check this? These should never be NULL. */
673 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
674 return -EIO;
675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500677 * No need to return error on this operation if tid invalidated and
678 * closed on server already e.g. due to tcp session crashing. Also,
679 * the tcon is no longer on the list, so no need to take lock before
680 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 */
Steve French268875b2009-06-25 00:29:21 +0000682 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Steve French50c2f752007-07-13 00:33:32 +0000685 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700686 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500687 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return rc;
Steve French133672e2007-11-13 22:41:37 +0000689
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400690 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700691 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500693 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Steve French50c2f752007-07-13 00:33:32 +0000695 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500696 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 if (rc == -EAGAIN)
698 rc = 0;
699
700 return rc;
701}
702
Jeff Layton766fdbb2011-01-11 07:24:21 -0500703/*
704 * This is a no-op for now. We're not really interested in the reply, but
705 * rather in the fact that the server sent one and that server->lstrp
706 * gets updated.
707 *
708 * FIXME: maybe we should consider checking that the reply matches request?
709 */
710static void
711cifs_echo_callback(struct mid_q_entry *mid)
712{
713 struct TCP_Server_Info *server = mid->callback_data;
714
715 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400716 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500717}
718
719int
720CIFSSMBEcho(struct TCP_Server_Info *server)
721{
722 ECHO_REQ *smb;
723 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800724 struct kvec iov[2];
725 struct smb_rqst rqst = { .rq_iov = iov,
726 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500727
Joe Perchesf96637b2013-05-04 22:12:25 -0500728 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500729
730 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
731 if (rc)
732 return rc;
733
Steve French26c9cb62017-05-02 13:35:20 -0500734 if (server->capabilities & CAP_UNICODE)
735 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
736
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000738 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500739 smb->hdr.WordCount = 1;
740 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400741 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000743 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800744
745 iov[0].iov_len = 4;
746 iov[0].iov_base = smb;
747 iov[1].iov_len = get_rfc1002_length(smb);
748 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500749
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800750 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400751 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500752 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500753 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500754
755 cifs_small_buf_release(smb);
756
757 return rc;
758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400761CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 LOGOFF_ANDX_REQ *pSMB;
764 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Joe Perchesf96637b2013-05-04 22:12:25 -0500766 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500767
768 /*
769 * BB: do we need to check validity of ses and server? They should
770 * always be valid since we have an active reference. If not, that
771 * should probably be a BUG()
772 */
773 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return -EIO;
775
Steve Frenchd7b619c2010-02-25 05:36:46 +0000776 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000777 if (ses->need_reconnect)
778 goto session_already_dead; /* no need to send SMBlogoff if uid
779 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
781 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000782 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return rc;
784 }
785
Pavel Shilovsky88257362012-05-23 14:01:59 +0400786 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700787
Jeff Layton38d77c52013-05-26 07:01:00 -0400788 if (ses->server->sign)
789 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 pSMB->hdr.Uid = ses->Suid;
792
793 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400794 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700795 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000796session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000797 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000800 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 error */
802 if (rc == -EAGAIN)
803 rc = 0;
804 return rc;
805}
806
807int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400808CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
809 const char *fileName, __u16 type,
810 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000811{
812 TRANSACTION2_SPI_REQ *pSMB = NULL;
813 TRANSACTION2_SPI_RSP *pSMBr = NULL;
814 struct unlink_psx_rq *pRqD;
815 int name_len;
816 int rc = 0;
817 int bytes_returned = 0;
818 __u16 params, param_offset, offset, byte_count;
819
Joe Perchesf96637b2013-05-04 22:12:25 -0500820 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000821PsxDelete:
822 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
823 (void **) &pSMBr);
824 if (rc)
825 return rc;
826
827 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
828 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600829 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
830 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000831 name_len++; /* trailing null */
832 name_len *= 2;
833 } else { /* BB add path length overrun check */
834 name_len = strnlen(fileName, PATH_MAX);
835 name_len++; /* trailing null */
836 strncpy(pSMB->FileName, fileName, name_len);
837 }
838
839 params = 6 + name_len;
840 pSMB->MaxParameterCount = cpu_to_le16(2);
841 pSMB->MaxDataCount = 0; /* BB double check this with jra */
842 pSMB->MaxSetupCount = 0;
843 pSMB->Reserved = 0;
844 pSMB->Flags = 0;
845 pSMB->Timeout = 0;
846 pSMB->Reserved2 = 0;
847 param_offset = offsetof(struct smb_com_transaction2_spi_req,
848 InformationLevel) - 4;
849 offset = param_offset + params;
850
851 /* Setup pointer to Request Data (inode type) */
852 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
853 pRqD->type = cpu_to_le16(type);
854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
855 pSMB->DataOffset = cpu_to_le16(offset);
856 pSMB->SetupCount = 1;
857 pSMB->Reserved3 = 0;
858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
859 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
860
861 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
862 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
863 pSMB->ParameterCount = cpu_to_le16(params);
864 pSMB->TotalParameterCount = pSMB->ParameterCount;
865 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
866 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000867 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000868 pSMB->ByteCount = cpu_to_le16(byte_count);
869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000871 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500872 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000873 cifs_buf_release(pSMB);
874
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400875 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000876
877 if (rc == -EAGAIN)
878 goto PsxDelete;
879
880 return rc;
881}
882
883int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700884CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
885 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
887 DELETE_FILE_REQ *pSMB = NULL;
888 DELETE_FILE_RSP *pSMBr = NULL;
889 int rc = 0;
890 int bytes_returned;
891 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500892 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894DelFileRetry:
895 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
896 (void **) &pSMBr);
897 if (rc)
898 return rc;
899
900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700901 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
902 PATH_MAX, cifs_sb->local_nls,
903 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 name_len++; /* trailing null */
905 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700906 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700907 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700909 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 }
911 pSMB->SearchAttributes =
912 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
913 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000914 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 pSMB->ByteCount = cpu_to_le16(name_len + 1);
916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400918 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000919 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500920 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 cifs_buf_release(pSMB);
923 if (rc == -EAGAIN)
924 goto DelFileRetry;
925
926 return rc;
927}
928
929int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400930CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
931 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
933 DELETE_DIRECTORY_REQ *pSMB = NULL;
934 DELETE_DIRECTORY_RSP *pSMBr = NULL;
935 int rc = 0;
936 int bytes_returned;
937 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500938 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Joe Perchesf96637b2013-05-04 22:12:25 -0500940 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941RmDirRetry:
942 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
943 (void **) &pSMBr);
944 if (rc)
945 return rc;
946
947 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400948 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
949 PATH_MAX, cifs_sb->local_nls,
950 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 name_len++; /* trailing null */
952 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700953 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400954 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400956 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 }
958
959 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000960 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 pSMB->ByteCount = cpu_to_le16(name_len + 1);
962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400964 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000965 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500966 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968 cifs_buf_release(pSMB);
969 if (rc == -EAGAIN)
970 goto RmDirRetry;
971 return rc;
972}
973
974int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300975CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
976 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 int rc = 0;
979 CREATE_DIRECTORY_REQ *pSMB = NULL;
980 CREATE_DIRECTORY_RSP *pSMBr = NULL;
981 int bytes_returned;
982 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500983 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Joe Perchesf96637b2013-05-04 22:12:25 -0500985 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986MkDirRetry:
987 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
988 (void **) &pSMBr);
989 if (rc)
990 return rc;
991
992 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600993 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300994 PATH_MAX, cifs_sb->local_nls,
995 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 name_len++; /* trailing null */
997 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700998 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 name_len = strnlen(name, PATH_MAX);
1000 name_len++; /* trailing null */
1001 strncpy(pSMB->DirName, name, name_len);
1002 }
1003
1004 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001005 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001009 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001010 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001011 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 cifs_buf_release(pSMB);
1014 if (rc == -EAGAIN)
1015 goto MkDirRetry;
1016 return rc;
1017}
1018
Steve French2dd29d32007-04-23 22:07:35 +00001019int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001020CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1021 __u32 posix_flags, __u64 mode, __u16 *netfid,
1022 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1023 const char *name, const struct nls_table *nls_codepage,
1024 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001025{
1026 TRANSACTION2_SPI_REQ *pSMB = NULL;
1027 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1028 int name_len;
1029 int rc = 0;
1030 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001031 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001032 OPEN_PSX_REQ *pdata;
1033 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001034
Joe Perchesf96637b2013-05-04 22:12:25 -05001035 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001036PsxCreat:
1037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1038 (void **) &pSMBr);
1039 if (rc)
1040 return rc;
1041
1042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1043 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001044 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1045 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001046 name_len++; /* trailing null */
1047 name_len *= 2;
1048 } else { /* BB improve the check for buffer overruns BB */
1049 name_len = strnlen(name, PATH_MAX);
1050 name_len++; /* trailing null */
1051 strncpy(pSMB->FileName, name, name_len);
1052 }
1053
1054 params = 6 + name_len;
1055 count = sizeof(OPEN_PSX_REQ);
1056 pSMB->MaxParameterCount = cpu_to_le16(2);
1057 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1058 pSMB->MaxSetupCount = 0;
1059 pSMB->Reserved = 0;
1060 pSMB->Flags = 0;
1061 pSMB->Timeout = 0;
1062 pSMB->Reserved2 = 0;
1063 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001064 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001065 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001066 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001067 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001068 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001069 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001070 pdata->OpenFlags = cpu_to_le32(*pOplock);
1071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1072 pSMB->DataOffset = cpu_to_le16(offset);
1073 pSMB->SetupCount = 1;
1074 pSMB->Reserved3 = 0;
1075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1076 byte_count = 3 /* pad */ + params + count;
1077
1078 pSMB->DataCount = cpu_to_le16(count);
1079 pSMB->ParameterCount = cpu_to_le16(params);
1080 pSMB->TotalDataCount = pSMB->DataCount;
1081 pSMB->TotalParameterCount = pSMB->ParameterCount;
1082 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1083 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001084 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001085 pSMB->ByteCount = cpu_to_le16(byte_count);
1086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1088 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001089 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001090 goto psx_create_err;
1091 }
1092
Joe Perchesf96637b2013-05-04 22:12:25 -05001093 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1095
Jeff Layton820a8032011-05-04 08:05:26 -04001096 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001097 rc = -EIO; /* bad smb */
1098 goto psx_create_err;
1099 }
1100
1101 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001102 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001103 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001104
Steve French2dd29d32007-04-23 22:07:35 +00001105 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001106 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001107 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1108 /* Let caller know file was created so we can set the mode. */
1109 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001110 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001111 *pOplock |= CIFS_CREATE_ACTION;
1112 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001113 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1114 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001115 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001116 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001117 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001118 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001119 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001120 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001121 goto psx_create_err;
1122 }
Steve French50c2f752007-07-13 00:33:32 +00001123 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001124 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001125 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001126 }
Steve French2dd29d32007-04-23 22:07:35 +00001127
1128psx_create_err:
1129 cifs_buf_release(pSMB);
1130
Steve French65bc98b2009-07-10 15:27:25 +00001131 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001132 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001133 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001134 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001135
1136 if (rc == -EAGAIN)
1137 goto PsxCreat;
1138
Steve French50c2f752007-07-13 00:33:32 +00001139 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001140}
1141
Steve Frencha9d02ad2005-08-24 23:06:05 -07001142static __u16 convert_disposition(int disposition)
1143{
1144 __u16 ofun = 0;
1145
1146 switch (disposition) {
1147 case FILE_SUPERSEDE:
1148 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1149 break;
1150 case FILE_OPEN:
1151 ofun = SMBOPEN_OAPPEND;
1152 break;
1153 case FILE_CREATE:
1154 ofun = SMBOPEN_OCREATE;
1155 break;
1156 case FILE_OPEN_IF:
1157 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1158 break;
1159 case FILE_OVERWRITE:
1160 ofun = SMBOPEN_OTRUNC;
1161 break;
1162 case FILE_OVERWRITE_IF:
1163 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1164 break;
1165 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001166 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167 ofun = SMBOPEN_OAPPEND; /* regular open */
1168 }
1169 return ofun;
1170}
1171
Jeff Layton35fc37d2008-05-14 10:22:03 -07001172static int
1173access_flags_to_smbopen_mode(const int access_flags)
1174{
1175 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1176
1177 if (masked_flags == GENERIC_READ)
1178 return SMBOPEN_READ;
1179 else if (masked_flags == GENERIC_WRITE)
1180 return SMBOPEN_WRITE;
1181
1182 /* just go for read/write */
1183 return SMBOPEN_READWRITE;
1184}
1185
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001187SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001189 const int access_flags, const int create_options, __u16 *netfid,
1190 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001191 const struct nls_table *nls_codepage, int remap)
1192{
1193 int rc = -EACCES;
1194 OPENX_REQ *pSMB = NULL;
1195 OPENX_RSP *pSMBr = NULL;
1196 int bytes_returned;
1197 int name_len;
1198 __u16 count;
1199
1200OldOpenRetry:
1201 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1202 (void **) &pSMBr);
1203 if (rc)
1204 return rc;
1205
1206 pSMB->AndXCommand = 0xFF; /* none */
1207
1208 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1209 count = 1; /* account for one byte pad to word boundary */
1210 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001211 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1212 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 name_len++; /* trailing null */
1214 name_len *= 2;
1215 } else { /* BB improve check for buffer overruns BB */
1216 count = 0; /* no pad */
1217 name_len = strnlen(fileName, PATH_MAX);
1218 name_len++; /* trailing null */
1219 strncpy(pSMB->fileName, fileName, name_len);
1220 }
1221 if (*pOplock & REQ_OPLOCK)
1222 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001223 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001224 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001225
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001227 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1229 /* set file as system file if special file such
1230 as fifo and server expecting SFU style and
1231 no Unix extensions */
1232
Steve French790fe572007-07-07 19:25:05 +00001233 if (create_options & CREATE_OPTION_SPECIAL)
1234 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001235 else /* BB FIXME BB */
1236 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
Jeff Layton67750fb2008-05-09 22:28:02 +00001238 if (create_options & CREATE_OPTION_READONLY)
1239 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240
1241 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001242/* pSMB->CreateOptions = cpu_to_le32(create_options &
1243 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001245
1246 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001247 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001249 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250
1251 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001253 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001254 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001256 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 } else {
1258 /* BB verify if wct == 15 */
1259
Steve French582d21e2008-05-13 04:54:12 +00001260/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261
1262 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1263 /* Let caller know file was created so we can set the mode. */
1264 /* Do we care about the CreateAction in any other cases? */
1265 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001266/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 *pOplock |= CIFS_CREATE_ACTION; */
1268 /* BB FIXME END */
1269
Steve French790fe572007-07-07 19:25:05 +00001270 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1272 pfile_info->LastAccessTime = 0; /* BB fixme */
1273 pfile_info->LastWriteTime = 0; /* BB fixme */
1274 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001275 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001276 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001278 pfile_info->AllocationSize =
1279 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1280 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001282 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 }
1284 }
1285
1286 cifs_buf_release(pSMB);
1287 if (rc == -EAGAIN)
1288 goto OldOpenRetry;
1289 return rc;
1290}
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001293CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1294 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001297 OPEN_REQ *req = NULL;
1298 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 int bytes_returned;
1300 int name_len;
1301 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001302 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1303 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001304 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001305 const struct nls_table *nls = cifs_sb->local_nls;
1306 int create_options = oparms->create_options;
1307 int desired_access = oparms->desired_access;
1308 int disposition = oparms->disposition;
1309 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
1311openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001312 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1313 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 if (rc)
1315 return rc;
1316
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001317 /* no commands go after this */
1318 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001320 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1321 /* account for one byte pad to word boundary */
1322 count = 1;
1323 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1324 path, PATH_MAX, nls, remap);
1325 /* trailing null */
1326 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001328 req->NameLength = cpu_to_le16(name_len);
1329 } else {
1330 /* BB improve check for buffer overruns BB */
1331 /* no pad */
1332 count = 0;
1333 name_len = strnlen(path, PATH_MAX);
1334 /* trailing null */
1335 name_len++;
1336 req->NameLength = cpu_to_le16(name_len);
1337 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001339
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001340 if (*oplock & REQ_OPLOCK)
1341 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1342 else if (*oplock & REQ_BATCHOPLOCK)
1343 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1344
1345 req->DesiredAccess = cpu_to_le32(desired_access);
1346 req->AllocationSize = 0;
1347
1348 /*
1349 * Set file as system file if special file such as fifo and server
1350 * expecting SFU style and no Unix extensions.
1351 */
1352 if (create_options & CREATE_OPTION_SPECIAL)
1353 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1354 else
1355 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1356
1357 /*
1358 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1359 * sensitive checks for other servers such as Samba.
1360 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001362 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Jeff Layton67750fb2008-05-09 22:28:02 +00001364 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001365 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001366
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001367 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1368 req->CreateDisposition = cpu_to_le32(disposition);
1369 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1370
Steve French09d1db52005-04-28 22:41:08 -07001371 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001372 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1373 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001376 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001378 req->ByteCount = cpu_to_le16(count);
1379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1380 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001381 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001383 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001384 cifs_buf_release(req);
1385 if (rc == -EAGAIN)
1386 goto openRetry;
1387 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001389
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001390 /* 1 byte no need to le_to_cpu */
1391 *oplock = rsp->OplockLevel;
1392 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001393 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001394
1395 /* Let caller know file was created so we can set the mode. */
1396 /* Do we care about the CreateAction in any other cases? */
1397 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1398 *oplock |= CIFS_CREATE_ACTION;
1399
1400 if (buf) {
1401 /* copy from CreationTime to Attributes */
1402 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1403 /* the file_info buf is endian converted by caller */
1404 buf->AllocationSize = rsp->AllocationSize;
1405 buf->EndOfFile = rsp->EndOfFile;
1406 buf->NumberOfLinks = cpu_to_le32(1);
1407 buf->DeletePending = 0;
1408 }
1409
1410 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return rc;
1412}
1413
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001414/*
1415 * Discard any remaining data in the current SMB. To do this, we borrow the
1416 * current bigbuf.
1417 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001418int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001419cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001420{
Pavel Shilovsky350be252017-04-10 10:31:33 -07001421 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001422 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001423
1424 while (remaining > 0) {
1425 int length;
1426
1427 length = cifs_read_from_socket(server, server->bigbuf,
1428 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001429 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001430 if (length < 0)
1431 return length;
1432 server->total_read += length;
1433 remaining -= length;
1434 }
1435
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001436 return 0;
1437}
1438
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001439static int
1440cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1441{
1442 int length;
1443 struct cifs_readdata *rdata = mid->callback_data;
1444
Pavel Shilovsky350be252017-04-10 10:31:33 -07001445 length = cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001446 dequeue_mid(mid, rdata->result);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001447 mid->resp_buf = server->smallbuf;
1448 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001449 return length;
1450}
1451
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001452int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1454{
1455 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001456 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001458 char *buf = server->smallbuf;
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001459 unsigned int buflen = get_rfc1002_length(buf) +
1460 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001461 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001462
Joe Perchesf96637b2013-05-04 22:12:25 -05001463 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1464 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465
1466 /*
1467 * read the rest of READ_RSP header (sans Data array), or whatever we
1468 * can if there's not enough data. At this point, we've read down to
1469 * the Mid.
1470 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001471 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001472 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001473
Al Viroa6137302016-01-09 19:37:16 -05001474 length = cifs_read_from_socket(server,
1475 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476 if (length < 0)
1477 return length;
1478 server->total_read += length;
1479
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001480 if (server->ops->is_session_expired &&
1481 server->ops->is_session_expired(buf)) {
1482 cifs_reconnect(server);
1483 wake_up(&server->response_q);
1484 return -1;
1485 }
1486
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001487 if (server->ops->is_status_pending &&
1488 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001489 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001490 return -1;
1491 }
1492
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001493 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001494 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001495 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001496 cifs_dbg(FYI, "%s: server returned error %d\n",
1497 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001498 return cifs_readv_discard(server, mid);
1499 }
1500
1501 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001502 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001503 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1504 __func__, server->total_read,
1505 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506 rdata->result = -EIO;
1507 return cifs_readv_discard(server, mid);
1508 }
1509
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001510 data_offset = server->ops->read_data_offset(buf) +
1511 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001512 if (data_offset < server->total_read) {
1513 /*
1514 * win2k8 sometimes sends an offset of 0 when the read
1515 * is beyond the EOF. Treat it as if the data starts just after
1516 * the header.
1517 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001518 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1519 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520 data_offset = server->total_read;
1521 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1522 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001523 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1524 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001525 rdata->result = -EIO;
1526 return cifs_readv_discard(server, mid);
1527 }
1528
Joe Perchesf96637b2013-05-04 22:12:25 -05001529 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1530 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531
1532 len = data_offset - server->total_read;
1533 if (len > 0) {
1534 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001535 length = cifs_read_from_socket(server,
1536 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001537 if (length < 0)
1538 return length;
1539 server->total_read += length;
1540 }
1541
1542 /* set up first iov for signature check */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001543 rdata->iov[0].iov_base = buf;
1544 rdata->iov[0].iov_len = 4;
1545 rdata->iov[1].iov_base = buf + 4;
1546 rdata->iov[1].iov_len = server->total_read - 4;
1547 cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
1548 rdata->iov[0].iov_base, server->total_read);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549
1550 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001551#ifdef CONFIG_CIFS_SMB_DIRECT
1552 use_rdma_mr = rdata->mr;
1553#endif
1554 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1555 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556 /* data_len is corrupt -- discard frame */
1557 rdata->result = -EIO;
1558 return cifs_readv_discard(server, mid);
1559 }
1560
Jeff Layton8321fec2012-09-19 06:22:32 -07001561 length = rdata->read_into_pages(server, rdata, data_len);
1562 if (length < 0)
1563 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001564
Jeff Layton8321fec2012-09-19 06:22:32 -07001565 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001566
Joe Perchesf96637b2013-05-04 22:12:25 -05001567 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1568 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001569
1570 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001571 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572 return cifs_readv_discard(server, mid);
1573
1574 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001575 mid->resp_buf = server->smallbuf;
1576 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577 return length;
1578}
1579
1580static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001581cifs_readv_callback(struct mid_q_entry *mid)
1582{
1583 struct cifs_readdata *rdata = mid->callback_data;
1584 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1585 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001586 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1587 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001588 .rq_pages = rdata->pages,
1589 .rq_npages = rdata->nr_pages,
1590 .rq_pagesz = rdata->pagesz,
1591 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001592
Joe Perchesf96637b2013-05-04 22:12:25 -05001593 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1594 __func__, mid->mid, mid->mid_state, rdata->result,
1595 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001596
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001597 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001598 case MID_RESPONSE_RECEIVED:
1599 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001600 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001601 int rc = 0;
1602
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001603 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001604 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001605 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001606 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1607 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608 }
1609 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001610 task_io_account_read(rdata->got_bytes);
1611 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001612 break;
1613 case MID_REQUEST_SUBMITTED:
1614 case MID_RETRY_NEEDED:
1615 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001616 if (server->sign && rdata->got_bytes)
1617 /* reset bytes number since we can not check a sign */
1618 rdata->got_bytes = 0;
1619 /* FIXME: should this be counted toward the initiating task? */
1620 task_io_account_read(rdata->got_bytes);
1621 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001622 break;
1623 default:
1624 rdata->result = -EIO;
1625 }
1626
Jeff Laytonda472fc2012-03-23 14:40:53 -04001627 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001628 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001629 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630}
1631
1632/* cifs_async_readv - send an async write, and set up mid to handle result */
1633int
1634cifs_async_readv(struct cifs_readdata *rdata)
1635{
1636 int rc;
1637 READ_REQ *smb = NULL;
1638 int wct;
1639 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001640 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1641 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001642
Joe Perchesf96637b2013-05-04 22:12:25 -05001643 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1644 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001645
1646 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1647 wct = 12;
1648 else {
1649 wct = 10; /* old style read */
1650 if ((rdata->offset >> 32) > 0) {
1651 /* can not handle this big offset for old */
1652 return -EIO;
1653 }
1654 }
1655
1656 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1657 if (rc)
1658 return rc;
1659
1660 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1661 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1662
1663 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001664 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001665 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1666 if (wct == 12)
1667 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1668 smb->Remaining = 0;
1669 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1670 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1671 if (wct == 12)
1672 smb->ByteCount = 0;
1673 else {
1674 /* old style read */
1675 struct smb_com_readx_req *smbr =
1676 (struct smb_com_readx_req *)smb;
1677 smbr->ByteCount = 0;
1678 }
1679
1680 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001681 rdata->iov[0].iov_base = smb;
1682 rdata->iov[0].iov_len = 4;
1683 rdata->iov[1].iov_base = (char *)smb + 4;
1684 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001685
Jeff Layton6993f742012-05-16 07:13:17 -04001686 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001687 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001688 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001689
1690 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001691 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001692 else
1693 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001694
1695 cifs_small_buf_release(smb);
1696 return rc;
1697}
1698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001700CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1701 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702{
1703 int rc = -EACCES;
1704 READ_REQ *pSMB = NULL;
1705 READ_RSP *pSMBr = NULL;
1706 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001707 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001708 int resp_buf_type = 0;
1709 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001710 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001711 __u32 pid = io_parms->pid;
1712 __u16 netfid = io_parms->netfid;
1713 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001714 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001715 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
Joe Perchesf96637b2013-05-04 22:12:25 -05001717 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001718 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001719 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001720 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001721 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001722 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001723 /* can not handle this big offset for old */
1724 return -EIO;
1725 }
1726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001729 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 if (rc)
1731 return rc;
1732
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001733 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1734 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1735
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 /* tcon and ses pointer are checked in smb_init */
1737 if (tcon->ses->server == NULL)
1738 return -ECONNABORTED;
1739
Steve Frenchec637e32005-12-12 20:53:18 -08001740 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001742 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001743 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001744 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001745
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 pSMB->Remaining = 0;
1747 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1748 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001749 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001750 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1751 else {
1752 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001753 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001754 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001755 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001756 }
Steve Frenchec637e32005-12-12 20:53:18 -08001757
1758 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001759 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001760 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1761 CIFS_LOG_ERROR, &rsp_iov);
1762 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001763 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001764 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001766 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 } else {
1768 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1769 data_length = data_length << 16;
1770 data_length += le16_to_cpu(pSMBr->DataLength);
1771 *nbytes = data_length;
1772
1773 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001774 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001776 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001777 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 rc = -EIO;
1779 *nbytes = 0;
1780 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001781 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001782 le16_to_cpu(pSMBr->DataOffset);
1783/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001784 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001785 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001786 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001787 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001788 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 }
1790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Steve French790fe572007-07-07 19:25:05 +00001792 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001793 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001794 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001795 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001796 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001797 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001798 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001799 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001800 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001801 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001802
1803 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 since file handle passed in no longer valid */
1805 return rc;
1806}
1807
Steve Frenchec637e32005-12-12 20:53:18 -08001808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001810CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001811 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812{
1813 int rc = -EACCES;
1814 WRITE_REQ *pSMB = NULL;
1815 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001816 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 __u32 bytes_sent;
1818 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001819 __u32 pid = io_parms->pid;
1820 __u16 netfid = io_parms->netfid;
1821 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001822 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001823 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
Steve Frencha24e2d72010-04-03 17:20:21 +00001825 *nbytes = 0;
1826
Joe Perchesf96637b2013-05-04 22:12:25 -05001827 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001828 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001829 return -ECONNABORTED;
1830
Steve French790fe572007-07-07 19:25:05 +00001831 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001832 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001833 else {
Steve French1c955182005-08-30 20:58:07 -07001834 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001835 if ((offset >> 32) > 0) {
1836 /* can not handle big offset for old srv */
1837 return -EIO;
1838 }
1839 }
Steve French1c955182005-08-30 20:58:07 -07001840
1841 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 (void **) &pSMBr);
1843 if (rc)
1844 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001845
1846 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1847 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 /* tcon and ses pointer are checked in smb_init */
1850 if (tcon->ses->server == NULL)
1851 return -ECONNABORTED;
1852
1853 pSMB->AndXCommand = 0xFF; /* none */
1854 pSMB->Fid = netfid;
1855 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001856 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001857 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 pSMB->Reserved = 0xFFFFFFFF;
1860 pSMB->WriteMode = 0;
1861 pSMB->Remaining = 0;
1862
Steve French50c2f752007-07-13 00:33:32 +00001863 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 can send more if LARGE_WRITE_X capability returned by the server and if
1865 our buffer is big enough or if we convert to iovecs on socket writes
1866 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001867 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1869 } else {
1870 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1871 & ~0xFF;
1872 }
1873
1874 if (bytes_sent > count)
1875 bytes_sent = count;
1876 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001877 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001878 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001879 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001880 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 /* No buffer */
1882 cifs_buf_release(pSMB);
1883 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001884 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001885 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001886 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001887 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001888 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1891 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001892 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001893
Steve French790fe572007-07-07 19:25:05 +00001894 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001895 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001896 else { /* old style write has byte count 4 bytes earlier
1897 so 4 bytes pad */
1898 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001899 (struct smb_com_writex_req *)pSMB;
1900 pSMBW->ByteCount = cpu_to_le16(byte_count);
1901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
1903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001905 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001907 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 } else {
1909 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1910 *nbytes = (*nbytes) << 16;
1911 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301912
1913 /*
1914 * Mask off high 16 bits when bytes written as returned by the
1915 * server is greater than bytes requested by the client. Some
1916 * OS/2 servers are known to set incorrect CountHigh values.
1917 */
1918 if (*nbytes > count)
1919 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 }
1921
1922 cifs_buf_release(pSMB);
1923
Steve French50c2f752007-07-13 00:33:32 +00001924 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 since file handle passed in no longer valid */
1926
1927 return rc;
1928}
1929
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001930void
1931cifs_writedata_release(struct kref *refcount)
1932{
1933 struct cifs_writedata *wdata = container_of(refcount,
1934 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001935#ifdef CONFIG_CIFS_SMB_DIRECT
1936 if (wdata->mr) {
1937 smbd_deregister_mr(wdata->mr);
1938 wdata->mr = NULL;
1939 }
1940#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001941
1942 if (wdata->cfile)
1943 cifsFileInfo_put(wdata->cfile);
1944
1945 kfree(wdata);
1946}
1947
1948/*
1949 * Write failed with a retryable error. Resend the write request. It's also
1950 * possible that the page was redirtied so re-clean the page.
1951 */
1952static void
1953cifs_writev_requeue(struct cifs_writedata *wdata)
1954{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001955 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001956 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001957 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001958 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001959
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001960 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1961 i = 0;
1962 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001963 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001964 struct cifs_writedata *wdata2;
1965 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001966
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001967 wsize = server->ops->wp_retry_size(inode);
1968 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001969 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001970 if (!nr_pages) {
1971 rc = -ENOTSUPP;
1972 break;
1973 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001974 cur_len = nr_pages * PAGE_SIZE;
1975 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001976 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001977 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001978 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001979 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001980 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001981
1982 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1983 if (!wdata2) {
1984 rc = -ENOMEM;
1985 break;
1986 }
1987
1988 for (j = 0; j < nr_pages; j++) {
1989 wdata2->pages[j] = wdata->pages[i + j];
1990 lock_page(wdata2->pages[j]);
1991 clear_page_dirty_for_io(wdata2->pages[j]);
1992 }
1993
1994 wdata2->sync_mode = wdata->sync_mode;
1995 wdata2->nr_pages = nr_pages;
1996 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001997 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001998 wdata2->tailsz = tailsz;
1999 wdata2->bytes = cur_len;
2000
2001 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2002 if (!wdata2->cfile) {
2003 cifs_dbg(VFS, "No writable handles for inode\n");
2004 rc = -EBADF;
2005 break;
2006 }
2007 wdata2->pid = wdata2->cfile->pid;
2008 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2009
2010 for (j = 0; j < nr_pages; j++) {
2011 unlock_page(wdata2->pages[j]);
2012 if (rc != 0 && rc != -EAGAIN) {
2013 SetPageError(wdata2->pages[j]);
2014 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002015 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002016 }
2017 }
2018
2019 if (rc) {
2020 kref_put(&wdata2->refcount, cifs_writedata_release);
2021 if (rc == -EAGAIN)
2022 continue;
2023 break;
2024 }
2025
2026 rest_len -= cur_len;
2027 i += nr_pages;
2028 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002029
2030 mapping_set_error(inode->i_mapping, rc);
2031 kref_put(&wdata->refcount, cifs_writedata_release);
2032}
2033
Jeff Laytonc2e87642012-03-23 14:40:55 -04002034void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002035cifs_writev_complete(struct work_struct *work)
2036{
2037 struct cifs_writedata *wdata = container_of(work,
2038 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002039 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040 int i = 0;
2041
2042 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002043 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002044 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002045 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002046 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2047 wdata->bytes);
2048 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2049 return cifs_writev_requeue(wdata);
2050
2051 for (i = 0; i < wdata->nr_pages; i++) {
2052 struct page *page = wdata->pages[i];
2053 if (wdata->result == -EAGAIN)
2054 __set_page_dirty_nobuffers(page);
2055 else if (wdata->result < 0)
2056 SetPageError(page);
2057 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002058 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002059 }
2060 if (wdata->result != -EAGAIN)
2061 mapping_set_error(inode->i_mapping, wdata->result);
2062 kref_put(&wdata->refcount, cifs_writedata_release);
2063}
2064
2065struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002066cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002067{
2068 struct cifs_writedata *wdata;
2069
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070 /* writedata + number of page pointers */
2071 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002072 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002073 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002074 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002075 INIT_LIST_HEAD(&wdata->list);
2076 init_completion(&wdata->done);
2077 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002078 }
2079 return wdata;
2080}
2081
2082/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002083 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002084 * workqueue completion task.
2085 */
2086static void
2087cifs_writev_callback(struct mid_q_entry *mid)
2088{
2089 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002090 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002091 unsigned int written;
2092 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2093
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002094 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095 case MID_RESPONSE_RECEIVED:
2096 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2097 if (wdata->result != 0)
2098 break;
2099
2100 written = le16_to_cpu(smb->CountHigh);
2101 written <<= 16;
2102 written += le16_to_cpu(smb->Count);
2103 /*
2104 * Mask off high 16 bits when bytes written as returned
2105 * by the server is greater than bytes requested by the
2106 * client. OS/2 servers are known to set incorrect
2107 * CountHigh values.
2108 */
2109 if (written > wdata->bytes)
2110 written &= 0xFFFF;
2111
2112 if (written < wdata->bytes)
2113 wdata->result = -ENOSPC;
2114 else
2115 wdata->bytes = written;
2116 break;
2117 case MID_REQUEST_SUBMITTED:
2118 case MID_RETRY_NEEDED:
2119 wdata->result = -EAGAIN;
2120 break;
2121 default:
2122 wdata->result = -EIO;
2123 break;
2124 }
2125
Jeff Laytonda472fc2012-03-23 14:40:53 -04002126 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002127 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002128 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002129}
2130
2131/* cifs_async_writev - send an async write, and set up mid to handle result */
2132int
Steve French4a5c80d2014-02-07 20:45:12 -06002133cifs_async_writev(struct cifs_writedata *wdata,
2134 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002135{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002136 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002137 WRITE_REQ *smb = NULL;
2138 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002139 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002140 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002141 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002142
2143 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2144 wct = 14;
2145 } else {
2146 wct = 12;
2147 if (wdata->offset >> 32 > 0) {
2148 /* can not handle big offset for old srv */
2149 return -EIO;
2150 }
2151 }
2152
2153 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2154 if (rc)
2155 goto async_writev_out;
2156
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002157 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2158 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002159
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002160 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002161 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002162 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2163 if (wct == 14)
2164 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2165 smb->Reserved = 0xFFFFFFFF;
2166 smb->WriteMode = 0;
2167 smb->Remaining = 0;
2168
2169 smb->DataOffset =
2170 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2171
2172 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002173 iov[0].iov_len = 4;
2174 iov[0].iov_base = smb;
2175 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2176 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002177
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002178 rqst.rq_iov = iov;
2179 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002180 rqst.rq_pages = wdata->pages;
2181 rqst.rq_npages = wdata->nr_pages;
2182 rqst.rq_pagesz = wdata->pagesz;
2183 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002184
Joe Perchesf96637b2013-05-04 22:12:25 -05002185 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2186 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002187
2188 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2189 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2190
2191 if (wct == 14) {
2192 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2193 put_bcc(wdata->bytes + 1, &smb->hdr);
2194 } else {
2195 /* wct == 12 */
2196 struct smb_com_writex_req *smbw =
2197 (struct smb_com_writex_req *)smb;
2198 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2199 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002200 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002201 }
2202
2203 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002204 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002205 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002206
2207 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002208 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002209 else
Steve French4a5c80d2014-02-07 20:45:12 -06002210 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002211
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002212async_writev_out:
2213 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002214 return rc;
2215}
2216
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002217int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002218CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002219 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220{
2221 int rc = -EACCES;
2222 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002223 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002224 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002225 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002226 __u32 pid = io_parms->pid;
2227 __u16 netfid = io_parms->netfid;
2228 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002229 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002230 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002231 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002233 *nbytes = 0;
2234
Joe Perchesf96637b2013-05-04 22:12:25 -05002235 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002236
Steve French4c3130e2008-12-09 00:28:16 +00002237 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002238 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002239 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002240 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002241 if ((offset >> 32) > 0) {
2242 /* can not handle big offset for old srv */
2243 return -EIO;
2244 }
2245 }
Steve French8cc64c62005-10-03 13:49:43 -07002246 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 if (rc)
2248 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002249
2250 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2251 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2252
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 /* tcon and ses pointer are checked in smb_init */
2254 if (tcon->ses->server == NULL)
2255 return -ECONNABORTED;
2256
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002257 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 pSMB->Fid = netfid;
2259 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002260 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002261 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 pSMB->Reserved = 0xFFFFFFFF;
2263 pSMB->WriteMode = 0;
2264 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002265
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002267 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
Steve French3e844692005-10-03 13:37:24 -07002269 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2270 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002271 /* header + 1 byte pad */
2272 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002273 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002274 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002275 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002276 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002277 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002278 pSMB->ByteCount = cpu_to_le16(count + 1);
2279 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002280 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002281 (struct smb_com_writex_req *)pSMB;
2282 pSMBW->ByteCount = cpu_to_le16(count + 5);
2283 }
Steve French3e844692005-10-03 13:37:24 -07002284 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002285 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002286 iov[0].iov_len = smb_hdr_len + 4;
2287 else /* wct == 12 pad bigger by four bytes */
2288 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002289
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002290 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2291 &rsp_iov);
2292 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002293 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002295 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002296 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002297 /* presumably this can not happen, but best to be safe */
2298 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002299 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002300 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002301 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2302 *nbytes = (*nbytes) << 16;
2303 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302304
2305 /*
2306 * Mask off high 16 bits when bytes written as returned by the
2307 * server is greater than bytes requested by the client. OS/2
2308 * servers are known to set incorrect CountHigh values.
2309 */
2310 if (*nbytes > count)
2311 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002314 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Steve French50c2f752007-07-13 00:33:32 +00002316 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 since file handle passed in no longer valid */
2318
2319 return rc;
2320}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002321
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002322int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2323 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002324 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2325{
2326 int rc = 0;
2327 LOCK_REQ *pSMB = NULL;
2328 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002329 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002330 int resp_buf_type;
2331 __u16 count;
2332
Joe Perchesf96637b2013-05-04 22:12:25 -05002333 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2334 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002335
2336 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2337 if (rc)
2338 return rc;
2339
2340 pSMB->Timeout = 0;
2341 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2342 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2343 pSMB->LockType = lock_type;
2344 pSMB->AndXCommand = 0xFF; /* none */
2345 pSMB->Fid = netfid; /* netfid stays le */
2346
2347 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2348 inc_rfc1001_len(pSMB, count);
2349 pSMB->ByteCount = cpu_to_le16(count);
2350
2351 iov[0].iov_base = (char *)pSMB;
2352 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2353 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2354 iov[1].iov_base = (char *)buf;
2355 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2356
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002357 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002358 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2359 &rsp_iov);
2360 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002361 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002362 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002363
2364 return rc;
2365}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002366
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002368CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002369 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002371 const __u32 numLock, const __u8 lockType,
2372 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373{
2374 int rc = 0;
2375 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002376/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002378 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 __u16 count;
2380
Joe Perchesf96637b2013-05-04 22:12:25 -05002381 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2382 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002383 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2384
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 if (rc)
2386 return rc;
2387
Steve French790fe572007-07-07 19:25:05 +00002388 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002389 /* no response expected */
2390 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002392 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002393 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2395 } else {
2396 pSMB->Timeout = 0;
2397 }
2398
2399 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2400 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2401 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002402 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 pSMB->AndXCommand = 0xFF; /* none */
2404 pSMB->Fid = smb_file_id; /* netfid stays le */
2405
Steve French790fe572007-07-07 19:25:05 +00002406 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002407 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 /* BB where to store pid high? */
2409 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2410 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2411 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2412 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2413 count = sizeof(LOCKING_ANDX_RANGE);
2414 } else {
2415 /* oplock break */
2416 count = 0;
2417 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002418 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 pSMB->ByteCount = cpu_to_le16(count);
2420
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002421 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002422 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002423 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002424 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002425 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002426 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002427 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002428 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002429 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Steve French50c2f752007-07-13 00:33:32 +00002431 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 since file handle passed in no longer valid */
2433 return rc;
2434}
2435
2436int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002437CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002438 const __u16 smb_file_id, const __u32 netpid,
2439 const loff_t start_offset, const __u64 len,
2440 struct file_lock *pLockData, const __u16 lock_type,
2441 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002442{
2443 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2444 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002445 struct cifs_posix_lock *parm_data;
2446 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002447 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002448 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002449 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002450 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002451 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002452 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002453
Joe Perchesf96637b2013-05-04 22:12:25 -05002454 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002455
Steve French08547b02006-02-28 22:39:25 +00002456 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2457
2458 if (rc)
2459 return rc;
2460
2461 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2462
Steve French50c2f752007-07-13 00:33:32 +00002463 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002464 pSMB->MaxSetupCount = 0;
2465 pSMB->Reserved = 0;
2466 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002467 pSMB->Reserved2 = 0;
2468 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2469 offset = param_offset + params;
2470
Steve French08547b02006-02-28 22:39:25 +00002471 count = sizeof(struct cifs_posix_lock);
2472 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002473 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002474 pSMB->SetupCount = 1;
2475 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002476 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002477 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2478 else
2479 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2480 byte_count = 3 /* pad */ + params + count;
2481 pSMB->DataCount = cpu_to_le16(count);
2482 pSMB->ParameterCount = cpu_to_le16(params);
2483 pSMB->TotalDataCount = pSMB->DataCount;
2484 pSMB->TotalParameterCount = pSMB->ParameterCount;
2485 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002486 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002487 (((char *) &pSMB->hdr.Protocol) + offset);
2488
2489 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002490 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002491 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002492 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002493 pSMB->Timeout = cpu_to_le32(-1);
2494 } else
2495 pSMB->Timeout = 0;
2496
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002497 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002498 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002499 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002500
2501 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002502 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002503 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2504 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002505 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002506 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002507 if (waitFlag) {
2508 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2509 (struct smb_hdr *) pSMBr, &bytes_returned);
2510 } else {
Steve French133672e2007-11-13 22:41:37 +00002511 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002512 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002513 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002514 &resp_buf_type, timeout, &rsp_iov);
2515 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002516 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002517 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002518
Steve French08547b02006-02-28 22:39:25 +00002519 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002520 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002521 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002522 /* lock structure can be returned on get */
2523 __u16 data_offset;
2524 __u16 data_count;
2525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002526
Jeff Layton820a8032011-05-04 08:05:26 -04002527 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002528 rc = -EIO; /* bad smb */
2529 goto plk_err_exit;
2530 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002531 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2532 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002533 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002534 rc = -EIO;
2535 goto plk_err_exit;
2536 }
2537 parm_data = (struct cifs_posix_lock *)
2538 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002539 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002540 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002541 else {
2542 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002543 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002544 pLockData->fl_type = F_RDLCK;
2545 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002546 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002547 pLockData->fl_type = F_WRLCK;
2548
Steve French5443d132011-03-13 05:08:25 +00002549 pLockData->fl_start = le64_to_cpu(parm_data->start);
2550 pLockData->fl_end = pLockData->fl_start +
2551 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002552 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002553 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002554 }
Steve French50c2f752007-07-13 00:33:32 +00002555
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002556plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002557 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002558
Steve French08547b02006-02-28 22:39:25 +00002559 /* Note: On -EAGAIN error only caller can retry on handle based calls
2560 since file handle passed in no longer valid */
2561
2562 return rc;
2563}
2564
2565
2566int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002567CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568{
2569 int rc = 0;
2570 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002571 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
2573/* do not retry on dead session on close */
2574 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002575 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 return 0;
2577 if (rc)
2578 return rc;
2579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002581 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002583 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002584 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002585 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002587 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002589 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 }
2591 }
2592
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002594 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 rc = 0;
2596
2597 return rc;
2598}
2599
2600int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002601CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002602{
2603 int rc = 0;
2604 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002605 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002606
2607 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2608 if (rc)
2609 return rc;
2610
2611 pSMB->FileID = (__u16) smb_file_id;
2612 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002613 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002614 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002615 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002616 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002617 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002618
2619 return rc;
2620}
2621
2622int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002623CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002624 const char *from_name, const char *to_name,
2625 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626{
2627 int rc = 0;
2628 RENAME_REQ *pSMB = NULL;
2629 RENAME_RSP *pSMBr = NULL;
2630 int bytes_returned;
2631 int name_len, name_len2;
2632 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002633 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634
Joe Perchesf96637b2013-05-04 22:12:25 -05002635 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636renameRetry:
2637 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2638 (void **) &pSMBr);
2639 if (rc)
2640 return rc;
2641
2642 pSMB->BufferFormat = 0x04;
2643 pSMB->SearchAttributes =
2644 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2645 ATTR_DIRECTORY);
2646
2647 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002648 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2649 from_name, PATH_MAX,
2650 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 name_len++; /* trailing null */
2652 name_len *= 2;
2653 pSMB->OldFileName[name_len] = 0x04; /* pad */
2654 /* protocol requires ASCII signature byte on Unicode string */
2655 pSMB->OldFileName[name_len + 1] = 0x00;
2656 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002657 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002658 to_name, PATH_MAX, cifs_sb->local_nls,
2659 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2661 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002662 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002663 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002665 strncpy(pSMB->OldFileName, from_name, name_len);
2666 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 name_len2++; /* trailing null */
2668 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002669 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 name_len2++; /* trailing null */
2671 name_len2++; /* signature byte */
2672 }
2673
2674 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002675 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 pSMB->ByteCount = cpu_to_le16(count);
2677
2678 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2679 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002680 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002681 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002682 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 cifs_buf_release(pSMB);
2685
2686 if (rc == -EAGAIN)
2687 goto renameRetry;
2688
2689 return rc;
2690}
2691
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002692int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002693 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002694 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695{
2696 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2697 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002698 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 char *data_offset;
2700 char dummy_string[30];
2701 int rc = 0;
2702 int bytes_returned = 0;
2703 int len_of_str;
2704 __u16 params, param_offset, offset, count, byte_count;
2705
Joe Perchesf96637b2013-05-04 22:12:25 -05002706 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2708 (void **) &pSMBr);
2709 if (rc)
2710 return rc;
2711
2712 params = 6;
2713 pSMB->MaxSetupCount = 0;
2714 pSMB->Reserved = 0;
2715 pSMB->Flags = 0;
2716 pSMB->Timeout = 0;
2717 pSMB->Reserved2 = 0;
2718 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2719 offset = param_offset + params;
2720
2721 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2722 rename_info = (struct set_file_rename *) data_offset;
2723 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002724 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 pSMB->SetupCount = 1;
2726 pSMB->Reserved3 = 0;
2727 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2728 byte_count = 3 /* pad */ + params;
2729 pSMB->ParameterCount = cpu_to_le16(params);
2730 pSMB->TotalParameterCount = pSMB->ParameterCount;
2731 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2732 pSMB->DataOffset = cpu_to_le16(offset);
2733 /* construct random name ".cifs_tmp<inodenum><mid>" */
2734 rename_info->overwrite = cpu_to_le32(1);
2735 rename_info->root_fid = 0;
2736 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002737 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002738 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002739 len_of_str =
2740 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002741 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002743 len_of_str =
2744 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002745 target_name, PATH_MAX, nls_codepage,
2746 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 }
2748 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002749 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 byte_count += count;
2751 pSMB->DataCount = cpu_to_le16(count);
2752 pSMB->TotalDataCount = pSMB->DataCount;
2753 pSMB->Fid = netfid;
2754 pSMB->InformationLevel =
2755 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2756 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002757 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 pSMB->ByteCount = cpu_to_le16(byte_count);
2759 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002761 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002762 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002763 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2764 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002765
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 cifs_buf_release(pSMB);
2767
2768 /* Note: On -EAGAIN error only caller can retry on handle based calls
2769 since file handle passed in no longer valid */
2770
2771 return rc;
2772}
2773
2774int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002775CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2776 const char *fromName, const __u16 target_tid, const char *toName,
2777 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778{
2779 int rc = 0;
2780 COPY_REQ *pSMB = NULL;
2781 COPY_RSP *pSMBr = NULL;
2782 int bytes_returned;
2783 int name_len, name_len2;
2784 __u16 count;
2785
Joe Perchesf96637b2013-05-04 22:12:25 -05002786 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787copyRetry:
2788 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2789 (void **) &pSMBr);
2790 if (rc)
2791 return rc;
2792
2793 pSMB->BufferFormat = 0x04;
2794 pSMB->Tid2 = target_tid;
2795
2796 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2797
2798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002799 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2800 fromName, PATH_MAX, nls_codepage,
2801 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 name_len++; /* trailing null */
2803 name_len *= 2;
2804 pSMB->OldFileName[name_len] = 0x04; /* pad */
2805 /* protocol requires ASCII signature byte on Unicode string */
2806 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002807 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002808 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2809 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2811 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002812 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 name_len = strnlen(fromName, PATH_MAX);
2814 name_len++; /* trailing null */
2815 strncpy(pSMB->OldFileName, fromName, name_len);
2816 name_len2 = strnlen(toName, PATH_MAX);
2817 name_len2++; /* trailing null */
2818 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2819 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2820 name_len2++; /* trailing null */
2821 name_len2++; /* signature byte */
2822 }
2823
2824 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002825 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 pSMB->ByteCount = cpu_to_le16(count);
2827
2828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2830 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002831 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2832 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 }
Steve French0d817bc2008-05-22 02:02:03 +00002834 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836 if (rc == -EAGAIN)
2837 goto copyRetry;
2838
2839 return rc;
2840}
2841
2842int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002843CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002845 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
2847 TRANSACTION2_SPI_REQ *pSMB = NULL;
2848 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2849 char *data_offset;
2850 int name_len;
2851 int name_len_target;
2852 int rc = 0;
2853 int bytes_returned = 0;
2854 __u16 params, param_offset, offset, byte_count;
2855
Joe Perchesf96637b2013-05-04 22:12:25 -05002856 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857createSymLinkRetry:
2858 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2859 (void **) &pSMBr);
2860 if (rc)
2861 return rc;
2862
2863 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2864 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002865 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2866 /* find define for this maxpathcomponent */
2867 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 name_len++; /* trailing null */
2869 name_len *= 2;
2870
Steve French50c2f752007-07-13 00:33:32 +00002871 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 name_len = strnlen(fromName, PATH_MAX);
2873 name_len++; /* trailing null */
2874 strncpy(pSMB->FileName, fromName, name_len);
2875 }
2876 params = 6 + name_len;
2877 pSMB->MaxSetupCount = 0;
2878 pSMB->Reserved = 0;
2879 pSMB->Flags = 0;
2880 pSMB->Timeout = 0;
2881 pSMB->Reserved2 = 0;
2882 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002883 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 offset = param_offset + params;
2885
2886 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2887 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2888 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002889 cifsConvertToUTF16((__le16 *) data_offset, toName,
2890 /* find define for this maxpathcomponent */
2891 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 name_len_target++; /* trailing null */
2893 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002894 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 name_len_target = strnlen(toName, PATH_MAX);
2896 name_len_target++; /* trailing null */
2897 strncpy(data_offset, toName, name_len_target);
2898 }
2899
2900 pSMB->MaxParameterCount = cpu_to_le16(2);
2901 /* BB find exact max on data count below from sess */
2902 pSMB->MaxDataCount = cpu_to_le16(1000);
2903 pSMB->SetupCount = 1;
2904 pSMB->Reserved3 = 0;
2905 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2906 byte_count = 3 /* pad */ + params + name_len_target;
2907 pSMB->DataCount = cpu_to_le16(name_len_target);
2908 pSMB->ParameterCount = cpu_to_le16(params);
2909 pSMB->TotalDataCount = pSMB->DataCount;
2910 pSMB->TotalParameterCount = pSMB->ParameterCount;
2911 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2912 pSMB->DataOffset = cpu_to_le16(offset);
2913 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2914 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002915 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 pSMB->ByteCount = cpu_to_le16(byte_count);
2917 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2918 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002919 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002920 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002921 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2922 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Steve French0d817bc2008-05-22 02:02:03 +00002924 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
2926 if (rc == -EAGAIN)
2927 goto createSymLinkRetry;
2928
2929 return rc;
2930}
2931
2932int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002933CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002935 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936{
2937 TRANSACTION2_SPI_REQ *pSMB = NULL;
2938 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2939 char *data_offset;
2940 int name_len;
2941 int name_len_target;
2942 int rc = 0;
2943 int bytes_returned = 0;
2944 __u16 params, param_offset, offset, byte_count;
2945
Joe Perchesf96637b2013-05-04 22:12:25 -05002946 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947createHardLinkRetry:
2948 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2949 (void **) &pSMBr);
2950 if (rc)
2951 return rc;
2952
2953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002954 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2955 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 name_len++; /* trailing null */
2957 name_len *= 2;
2958
Steve French50c2f752007-07-13 00:33:32 +00002959 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len = strnlen(toName, PATH_MAX);
2961 name_len++; /* trailing null */
2962 strncpy(pSMB->FileName, toName, name_len);
2963 }
2964 params = 6 + name_len;
2965 pSMB->MaxSetupCount = 0;
2966 pSMB->Reserved = 0;
2967 pSMB->Flags = 0;
2968 pSMB->Timeout = 0;
2969 pSMB->Reserved2 = 0;
2970 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002971 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 offset = param_offset + params;
2973
2974 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2975 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2976 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002977 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2978 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 name_len_target++; /* trailing null */
2980 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002981 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len_target = strnlen(fromName, PATH_MAX);
2983 name_len_target++; /* trailing null */
2984 strncpy(data_offset, fromName, name_len_target);
2985 }
2986
2987 pSMB->MaxParameterCount = cpu_to_le16(2);
2988 /* BB find exact max on data count below from sess*/
2989 pSMB->MaxDataCount = cpu_to_le16(1000);
2990 pSMB->SetupCount = 1;
2991 pSMB->Reserved3 = 0;
2992 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2993 byte_count = 3 /* pad */ + params + name_len_target;
2994 pSMB->ParameterCount = cpu_to_le16(params);
2995 pSMB->TotalParameterCount = pSMB->ParameterCount;
2996 pSMB->DataCount = cpu_to_le16(name_len_target);
2997 pSMB->TotalDataCount = pSMB->DataCount;
2998 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2999 pSMB->DataOffset = cpu_to_le16(offset);
3000 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3001 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003002 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 pSMB->ByteCount = cpu_to_le16(byte_count);
3004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003006 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003007 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003008 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3009 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
3011 cifs_buf_release(pSMB);
3012 if (rc == -EAGAIN)
3013 goto createHardLinkRetry;
3014
3015 return rc;
3016}
3017
3018int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003019CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003020 const char *from_name, const char *to_name,
3021 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022{
3023 int rc = 0;
3024 NT_RENAME_REQ *pSMB = NULL;
3025 RENAME_RSP *pSMBr = NULL;
3026 int bytes_returned;
3027 int name_len, name_len2;
3028 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003029 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
Joe Perchesf96637b2013-05-04 22:12:25 -05003031 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032winCreateHardLinkRetry:
3033
3034 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3035 (void **) &pSMBr);
3036 if (rc)
3037 return rc;
3038
3039 pSMB->SearchAttributes =
3040 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3041 ATTR_DIRECTORY);
3042 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3043 pSMB->ClusterCount = 0;
3044
3045 pSMB->BufferFormat = 0x04;
3046
3047 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3048 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003049 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3050 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 name_len++; /* trailing null */
3052 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003053
3054 /* protocol specifies ASCII buffer format (0x04) for unicode */
3055 pSMB->OldFileName[name_len] = 0x04;
3056 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003058 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003059 to_name, PATH_MAX, cifs_sb->local_nls,
3060 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3062 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003063 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003064 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003066 strncpy(pSMB->OldFileName, from_name, name_len);
3067 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 name_len2++; /* trailing null */
3069 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003070 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 name_len2++; /* trailing null */
3072 name_len2++; /* signature byte */
3073 }
3074
3075 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003076 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 pSMB->ByteCount = cpu_to_le16(count);
3078
3079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003081 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003082 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003083 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003084
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 cifs_buf_release(pSMB);
3086 if (rc == -EAGAIN)
3087 goto winCreateHardLinkRetry;
3088
3089 return rc;
3090}
3091
3092int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003093CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003094 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003095 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096{
3097/* SMB_QUERY_FILE_UNIX_LINK */
3098 TRANSACTION2_QPI_REQ *pSMB = NULL;
3099 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3100 int rc = 0;
3101 int bytes_returned;
3102 int name_len;
3103 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003104 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
Joe Perchesf96637b2013-05-04 22:12:25 -05003106 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108querySymLinkRetry:
3109 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3110 (void **) &pSMBr);
3111 if (rc)
3112 return rc;
3113
3114 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3115 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003116 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3117 searchName, PATH_MAX, nls_codepage,
3118 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 name_len++; /* trailing null */
3120 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003121 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 name_len = strnlen(searchName, PATH_MAX);
3123 name_len++; /* trailing null */
3124 strncpy(pSMB->FileName, searchName, name_len);
3125 }
3126
3127 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3128 pSMB->TotalDataCount = 0;
3129 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003130 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 pSMB->MaxSetupCount = 0;
3132 pSMB->Reserved = 0;
3133 pSMB->Flags = 0;
3134 pSMB->Timeout = 0;
3135 pSMB->Reserved2 = 0;
3136 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003137 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 pSMB->DataCount = 0;
3139 pSMB->DataOffset = 0;
3140 pSMB->SetupCount = 1;
3141 pSMB->Reserved3 = 0;
3142 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3143 byte_count = params + 1 /* pad */ ;
3144 pSMB->TotalParameterCount = cpu_to_le16(params);
3145 pSMB->ParameterCount = pSMB->TotalParameterCount;
3146 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3147 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003148 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 pSMB->ByteCount = cpu_to_le16(byte_count);
3150
3151 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3152 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3153 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003154 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 } else {
3156 /* decode response */
3157
3158 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003160 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003161 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003163 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003164 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165
Jeff Layton460b9692009-04-30 07:17:56 -04003166 data_start = ((char *) &pSMBr->hdr.Protocol) +
3167 le16_to_cpu(pSMBr->t2.DataOffset);
3168
Steve French0e0d2cf2009-05-01 05:27:32 +00003169 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3170 is_unicode = true;
3171 else
3172 is_unicode = false;
3173
Steve French737b7582005-04-28 22:41:06 -07003174 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003175 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3176 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003177 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003178 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 }
3180 }
3181 cifs_buf_release(pSMB);
3182 if (rc == -EAGAIN)
3183 goto querySymLinkRetry;
3184 return rc;
3185}
3186
Steve Frenchc52a95542011-02-24 06:16:22 +00003187/*
3188 * Recent Windows versions now create symlinks more frequently
3189 * and they use the "reparse point" mechanism below. We can of course
3190 * do symlinks nicely to Samba and other servers which support the
3191 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3192 * "MF" symlinks optionally, but for recent Windows we really need to
3193 * reenable the code below and fix the cifs_symlink callers to handle this.
3194 * In the interim this code has been moved to its own config option so
3195 * it is not compiled in by default until callers fixed up and more tested.
3196 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003198CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3199 __u16 fid, char **symlinkinfo,
3200 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201{
3202 int rc = 0;
3203 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003204 struct smb_com_transaction_ioctl_req *pSMB;
3205 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003206 bool is_unicode;
3207 unsigned int sub_len;
3208 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003209 struct reparse_symlink_data *reparse_buf;
3210 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003211 __u32 data_offset, data_count;
3212 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003214 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3216 (void **) &pSMBr);
3217 if (rc)
3218 return rc;
3219
3220 pSMB->TotalParameterCount = 0 ;
3221 pSMB->TotalDataCount = 0;
3222 pSMB->MaxParameterCount = cpu_to_le32(2);
3223 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003224 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 pSMB->MaxSetupCount = 4;
3226 pSMB->Reserved = 0;
3227 pSMB->ParameterOffset = 0;
3228 pSMB->DataCount = 0;
3229 pSMB->DataOffset = 0;
3230 pSMB->SetupCount = 4;
3231 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3232 pSMB->ParameterCount = pSMB->TotalParameterCount;
3233 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3234 pSMB->IsFsctl = 1; /* FSCTL */
3235 pSMB->IsRootFlag = 0;
3236 pSMB->Fid = fid; /* file handle always le */
3237 pSMB->ByteCount = 0;
3238
3239 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3240 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3241 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003242 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003243 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 }
Steve French989c7e52009-05-02 05:32:20 +00003245
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003246 data_offset = le32_to_cpu(pSMBr->DataOffset);
3247 data_count = le32_to_cpu(pSMBr->DataCount);
3248 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3249 /* BB also check enough total bytes returned */
3250 rc = -EIO; /* bad smb */
3251 goto qreparse_out;
3252 }
3253 if (!data_count || (data_count > 2048)) {
3254 rc = -EIO;
3255 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3256 goto qreparse_out;
3257 }
3258 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003259 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003260 ((char *)&pSMBr->hdr.Protocol + data_offset);
3261 if ((char *)reparse_buf >= end_of_smb) {
3262 rc = -EIO;
3263 goto qreparse_out;
3264 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003265 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3266 cifs_dbg(FYI, "NFS style reparse tag\n");
3267 posix_buf = (struct reparse_posix_data *)reparse_buf;
3268
3269 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3270 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3271 le64_to_cpu(posix_buf->InodeType));
3272 rc = -EOPNOTSUPP;
3273 goto qreparse_out;
3274 }
3275 is_unicode = true;
3276 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3277 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3278 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3279 rc = -EIO;
3280 goto qreparse_out;
3281 }
3282 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3283 sub_len, is_unicode, nls_codepage);
3284 goto qreparse_out;
3285 } else if (reparse_buf->ReparseTag !=
3286 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3287 rc = -EOPNOTSUPP;
3288 goto qreparse_out;
3289 }
3290
3291 /* Reparse tag is NTFS symlink */
3292 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3293 reparse_buf->PathBuffer;
3294 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3295 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003296 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3297 rc = -EIO;
3298 goto qreparse_out;
3299 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003300 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3301 is_unicode = true;
3302 else
3303 is_unicode = false;
3304
3305 /* BB FIXME investigate remapping reserved chars here */
3306 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3307 nls_codepage);
3308 if (!*symlinkinfo)
3309 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003311 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003313 /*
3314 * Note: On -EAGAIN error only caller can retry on handle based calls
3315 * since file handle passed in no longer valid.
3316 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 return rc;
3318}
3319
Steve Frenchc7f508a2013-10-14 15:27:32 -05003320int
3321CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3322 __u16 fid)
3323{
3324 int rc = 0;
3325 int bytes_returned;
3326 struct smb_com_transaction_compr_ioctl_req *pSMB;
3327 struct smb_com_transaction_ioctl_rsp *pSMBr;
3328
3329 cifs_dbg(FYI, "Set compression for %u\n", fid);
3330 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3331 (void **) &pSMBr);
3332 if (rc)
3333 return rc;
3334
3335 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3336
3337 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003338 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003339 pSMB->MaxParameterCount = 0;
3340 pSMB->MaxDataCount = 0;
3341 pSMB->MaxSetupCount = 4;
3342 pSMB->Reserved = 0;
3343 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003344 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003345 pSMB->DataOffset =
3346 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3347 compression_state) - 4); /* 84 */
3348 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003349 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003350 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003351 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003352 pSMB->IsFsctl = 1; /* FSCTL */
3353 pSMB->IsRootFlag = 0;
3354 pSMB->Fid = fid; /* file handle always le */
3355 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003356 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003357 inc_rfc1001_len(pSMB, 5);
3358
3359 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3361 if (rc)
3362 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3363
3364 cifs_buf_release(pSMB);
3365
3366 /*
3367 * Note: On -EAGAIN error only caller can retry on handle based calls
3368 * since file handle passed in no longer valid.
3369 */
3370 return rc;
3371}
3372
3373
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374#ifdef CONFIG_CIFS_POSIX
3375
3376/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003377static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003378 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379{
3380 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003381 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3382 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3383 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003384/*
3385 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3386 ace->e_perm, ace->e_tag, ace->e_id);
3387*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388
3389 return;
3390}
3391
3392/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003393static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3394 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395{
3396 int size = 0;
3397 int i;
3398 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003399 struct cifs_posix_ace *pACE;
3400 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003401 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402
3403 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3404 return -EOPNOTSUPP;
3405
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003406 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 count = le16_to_cpu(cifs_acl->access_entry_count);
3408 pACE = &cifs_acl->ace_array[0];
3409 size = sizeof(struct cifs_posix_acl);
3410 size += sizeof(struct cifs_posix_ace) * count;
3411 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003412 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003413 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3414 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 return -EINVAL;
3416 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003417 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 count = le16_to_cpu(cifs_acl->access_entry_count);
3419 size = sizeof(struct cifs_posix_acl);
3420 size += sizeof(struct cifs_posix_ace) * count;
3421/* skip past access ACEs to get to default ACEs */
3422 pACE = &cifs_acl->ace_array[count];
3423 count = le16_to_cpu(cifs_acl->default_entry_count);
3424 size += sizeof(struct cifs_posix_ace) * count;
3425 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003426 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 return -EINVAL;
3428 } else {
3429 /* illegal type */
3430 return -EINVAL;
3431 }
3432
3433 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003434 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003435 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003436 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 return -ERANGE;
3438 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003439 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3440
Steve Frenchff7feac2005-11-15 16:45:16 -08003441 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003442 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003443 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003444 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 }
3446 }
3447 return size;
3448}
3449
Steve French50c2f752007-07-13 00:33:32 +00003450static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003451 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452{
3453 __u16 rc = 0; /* 0 = ACL converted ok */
3454
Steve Frenchff7feac2005-11-15 16:45:16 -08003455 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3456 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003458 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 /* Probably no need to le convert -1 on any arch but can not hurt */
3460 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003461 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003462 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003463/*
3464 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3465 ace->e_perm, ace->e_tag, ace->e_id);
3466*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 return rc;
3468}
3469
3470/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003471static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3472 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473{
3474 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003475 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003476 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003477 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 int count;
3479 int i;
3480
Steve French790fe572007-07-07 19:25:05 +00003481 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 return 0;
3483
3484 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003485 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3486 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003487 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003488 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3489 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 return 0;
3491 }
3492 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003493 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003494 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003495 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003496 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003497 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003498 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003499 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003500 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 return 0;
3502 }
Steve French50c2f752007-07-13 00:33:32 +00003503 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003504 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003505 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 /* ACE not converted */
3507 break;
3508 }
3509 }
Steve French790fe572007-07-07 19:25:05 +00003510 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3512 rc += sizeof(struct cifs_posix_acl);
3513 /* BB add check to make sure ACL does not overflow SMB */
3514 }
3515 return rc;
3516}
3517
3518int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003519CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003520 const unsigned char *searchName,
3521 char *acl_inf, const int buflen, const int acl_type,
3522 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523{
3524/* SMB_QUERY_POSIX_ACL */
3525 TRANSACTION2_QPI_REQ *pSMB = NULL;
3526 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3527 int rc = 0;
3528 int bytes_returned;
3529 int name_len;
3530 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003531
Joe Perchesf96637b2013-05-04 22:12:25 -05003532 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534queryAclRetry:
3535 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3536 (void **) &pSMBr);
3537 if (rc)
3538 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003539
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3541 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003542 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3543 searchName, PATH_MAX, nls_codepage,
3544 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 name_len++; /* trailing null */
3546 name_len *= 2;
3547 pSMB->FileName[name_len] = 0;
3548 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003549 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 name_len = strnlen(searchName, PATH_MAX);
3551 name_len++; /* trailing null */
3552 strncpy(pSMB->FileName, searchName, name_len);
3553 }
3554
3555 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3556 pSMB->TotalDataCount = 0;
3557 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003558 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 pSMB->MaxDataCount = cpu_to_le16(4000);
3560 pSMB->MaxSetupCount = 0;
3561 pSMB->Reserved = 0;
3562 pSMB->Flags = 0;
3563 pSMB->Timeout = 0;
3564 pSMB->Reserved2 = 0;
3565 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003566 offsetof(struct smb_com_transaction2_qpi_req,
3567 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 pSMB->DataCount = 0;
3569 pSMB->DataOffset = 0;
3570 pSMB->SetupCount = 1;
3571 pSMB->Reserved3 = 0;
3572 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3573 byte_count = params + 1 /* pad */ ;
3574 pSMB->TotalParameterCount = cpu_to_le16(params);
3575 pSMB->ParameterCount = pSMB->TotalParameterCount;
3576 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3577 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003578 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 pSMB->ByteCount = cpu_to_le16(byte_count);
3580
3581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3582 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003583 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003585 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 } else {
3587 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003591 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 rc = -EIO; /* bad smb */
3593 else {
3594 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3595 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3596 rc = cifs_copy_posix_acl(acl_inf,
3597 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003598 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 }
3600 }
3601 cifs_buf_release(pSMB);
3602 if (rc == -EAGAIN)
3603 goto queryAclRetry;
3604 return rc;
3605}
3606
3607int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003608CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003609 const unsigned char *fileName,
3610 const char *local_acl, const int buflen,
3611 const int acl_type,
3612 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613{
3614 struct smb_com_transaction2_spi_req *pSMB = NULL;
3615 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3616 char *parm_data;
3617 int name_len;
3618 int rc = 0;
3619 int bytes_returned = 0;
3620 __u16 params, byte_count, data_count, param_offset, offset;
3621
Joe Perchesf96637b2013-05-04 22:12:25 -05003622 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623setAclRetry:
3624 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003625 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 if (rc)
3627 return rc;
3628 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3629 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003630 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3631 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 name_len++; /* trailing null */
3633 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003634 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 name_len = strnlen(fileName, PATH_MAX);
3636 name_len++; /* trailing null */
3637 strncpy(pSMB->FileName, fileName, name_len);
3638 }
3639 params = 6 + name_len;
3640 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003641 /* BB find max SMB size from sess */
3642 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 pSMB->MaxSetupCount = 0;
3644 pSMB->Reserved = 0;
3645 pSMB->Flags = 0;
3646 pSMB->Timeout = 0;
3647 pSMB->Reserved2 = 0;
3648 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003649 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 offset = param_offset + params;
3651 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3652 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3653
3654 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003655 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656
Steve French790fe572007-07-07 19:25:05 +00003657 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 rc = -EOPNOTSUPP;
3659 goto setACLerrorExit;
3660 }
3661 pSMB->DataOffset = cpu_to_le16(offset);
3662 pSMB->SetupCount = 1;
3663 pSMB->Reserved3 = 0;
3664 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3665 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3666 byte_count = 3 /* pad */ + params + data_count;
3667 pSMB->DataCount = cpu_to_le16(data_count);
3668 pSMB->TotalDataCount = pSMB->DataCount;
3669 pSMB->ParameterCount = cpu_to_le16(params);
3670 pSMB->TotalParameterCount = pSMB->ParameterCount;
3671 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003672 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 pSMB->ByteCount = cpu_to_le16(byte_count);
3674 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003675 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003676 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003677 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
3679setACLerrorExit:
3680 cifs_buf_release(pSMB);
3681 if (rc == -EAGAIN)
3682 goto setAclRetry;
3683 return rc;
3684}
3685
Steve Frenchf654bac2005-04-28 22:41:04 -07003686/* BB fix tabs in this function FIXME BB */
3687int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003688CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003689 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003690{
Steve French50c2f752007-07-13 00:33:32 +00003691 int rc = 0;
3692 struct smb_t2_qfi_req *pSMB = NULL;
3693 struct smb_t2_qfi_rsp *pSMBr = NULL;
3694 int bytes_returned;
3695 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003696
Joe Perchesf96637b2013-05-04 22:12:25 -05003697 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003698 if (tcon == NULL)
3699 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003700
3701GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003702 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3703 (void **) &pSMBr);
3704 if (rc)
3705 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003706
Steve Frenchad7a2922008-02-07 23:25:02 +00003707 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003708 pSMB->t2.TotalDataCount = 0;
3709 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3710 /* BB find exact max data count below from sess structure BB */
3711 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3712 pSMB->t2.MaxSetupCount = 0;
3713 pSMB->t2.Reserved = 0;
3714 pSMB->t2.Flags = 0;
3715 pSMB->t2.Timeout = 0;
3716 pSMB->t2.Reserved2 = 0;
3717 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3718 Fid) - 4);
3719 pSMB->t2.DataCount = 0;
3720 pSMB->t2.DataOffset = 0;
3721 pSMB->t2.SetupCount = 1;
3722 pSMB->t2.Reserved3 = 0;
3723 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3724 byte_count = params + 1 /* pad */ ;
3725 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3726 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3727 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3728 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003729 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003730 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003731 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003732
Steve French790fe572007-07-07 19:25:05 +00003733 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3734 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3735 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003736 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003737 } else {
3738 /* decode response */
3739 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003740 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003741 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003742 /* If rc should we check for EOPNOSUPP and
3743 disable the srvino flag? or in caller? */
3744 rc = -EIO; /* bad smb */
3745 else {
3746 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3747 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3748 struct file_chattr_info *pfinfo;
3749 /* BB Do we need a cast or hash here ? */
3750 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003751 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003752 rc = -EIO;
3753 goto GetExtAttrOut;
3754 }
3755 pfinfo = (struct file_chattr_info *)
3756 (data_offset + (char *) &pSMBr->hdr.Protocol);
3757 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003758 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003759 }
3760 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003761GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003762 cifs_buf_release(pSMB);
3763 if (rc == -EAGAIN)
3764 goto GetExtAttrRetry;
3765 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003766}
3767
Steve Frenchf654bac2005-04-28 22:41:04 -07003768#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
Jeff Layton79df1ba2010-12-06 12:52:08 -05003770#ifdef CONFIG_CIFS_ACL
3771/*
3772 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3773 * all NT TRANSACTS that we init here have total parm and data under about 400
3774 * bytes (to fit in small cifs buffer size), which is the case so far, it
3775 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3776 * returned setup area) and MaxParameterCount (returned parms size) must be set
3777 * by caller
3778 */
3779static int
3780smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003781 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003782 void **ret_buf)
3783{
3784 int rc;
3785 __u32 temp_offset;
3786 struct smb_com_ntransact_req *pSMB;
3787
3788 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3789 (void **)&pSMB);
3790 if (rc)
3791 return rc;
3792 *ret_buf = (void *)pSMB;
3793 pSMB->Reserved = 0;
3794 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3795 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003796 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003797 pSMB->ParameterCount = pSMB->TotalParameterCount;
3798 pSMB->DataCount = pSMB->TotalDataCount;
3799 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3800 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3801 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3802 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3803 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3804 pSMB->SubCommand = cpu_to_le16(sub_command);
3805 return 0;
3806}
3807
3808static int
3809validate_ntransact(char *buf, char **ppparm, char **ppdata,
3810 __u32 *pparmlen, __u32 *pdatalen)
3811{
3812 char *end_of_smb;
3813 __u32 data_count, data_offset, parm_count, parm_offset;
3814 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003815 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003816
3817 *pdatalen = 0;
3818 *pparmlen = 0;
3819
3820 if (buf == NULL)
3821 return -EINVAL;
3822
3823 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3824
Jeff Layton820a8032011-05-04 08:05:26 -04003825 bcc = get_bcc(&pSMBr->hdr);
3826 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003827 (char *)&pSMBr->ByteCount;
3828
3829 data_offset = le32_to_cpu(pSMBr->DataOffset);
3830 data_count = le32_to_cpu(pSMBr->DataCount);
3831 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3832 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3833
3834 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3835 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3836
3837 /* should we also check that parm and data areas do not overlap? */
3838 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003839 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003840 return -EINVAL;
3841 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003842 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003843 return -EINVAL;
3844 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003845 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003846 return -EINVAL;
3847 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003848 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3849 *ppdata, data_count, (data_count + *ppdata),
3850 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003851 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003852 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003853 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003854 return -EINVAL;
3855 }
3856 *pdatalen = data_count;
3857 *pparmlen = parm_count;
3858 return 0;
3859}
3860
Steve French0a4b92c2006-01-12 15:44:21 -08003861/* Get Security Descriptor (by handle) from remote server for a file or dir */
3862int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003863CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003864 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003865{
3866 int rc = 0;
3867 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003868 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003869 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003870 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003871
Joe Perchesf96637b2013-05-04 22:12:25 -05003872 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003873
Steve French630f3f0c2007-10-25 21:17:17 +00003874 *pbuflen = 0;
3875 *acl_inf = NULL;
3876
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003877 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003878 8 /* parm len */, tcon, (void **) &pSMB);
3879 if (rc)
3880 return rc;
3881
3882 pSMB->MaxParameterCount = cpu_to_le32(4);
3883 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3884 pSMB->MaxSetupCount = 0;
3885 pSMB->Fid = fid; /* file handle always le */
3886 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3887 CIFS_ACL_DACL);
3888 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003889 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003890 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003891 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003892
Steve Frencha761ac52007-10-18 21:45:27 +00003893 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003894 0, &rsp_iov);
3895 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003896 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003897 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003898 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003899 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003900 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003901 __u32 parm_len;
3902 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003903 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003904 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003905
3906/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003907 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003908 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003909 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003910 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003911 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003912
Joe Perchesf96637b2013-05-04 22:12:25 -05003913 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3914 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003915
3916 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3917 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003918 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003919 goto qsec_out;
3920 }
3921
3922/* BB check that data area is minimum length and as big as acl_len */
3923
Steve Frenchaf6f4612007-10-16 18:40:37 +00003924 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003925 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003926 cifs_dbg(VFS, "acl length %d does not match %d\n",
3927 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003928 if (*pbuflen > acl_len)
3929 *pbuflen = acl_len;
3930 }
Steve French0a4b92c2006-01-12 15:44:21 -08003931
Steve French630f3f0c2007-10-25 21:17:17 +00003932 /* check if buffer is big enough for the acl
3933 header followed by the smallest SID */
3934 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3935 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003936 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003937 rc = -EINVAL;
3938 *pbuflen = 0;
3939 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003940 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003941 if (*acl_inf == NULL) {
3942 *pbuflen = 0;
3943 rc = -ENOMEM;
3944 }
Steve French630f3f0c2007-10-25 21:17:17 +00003945 }
Steve French0a4b92c2006-01-12 15:44:21 -08003946 }
3947qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003948 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003949 return rc;
3950}
Steve French97837582007-12-31 07:47:21 +00003951
3952int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003953CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003954 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003955{
3956 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3957 int rc = 0;
3958 int bytes_returned = 0;
3959 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003960 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003961
3962setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003963 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003964 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003965 return rc;
Steve French97837582007-12-31 07:47:21 +00003966
3967 pSMB->MaxSetupCount = 0;
3968 pSMB->Reserved = 0;
3969
3970 param_count = 8;
3971 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3972 data_count = acllen;
3973 data_offset = param_offset + param_count;
3974 byte_count = 3 /* pad */ + param_count;
3975
3976 pSMB->DataCount = cpu_to_le32(data_count);
3977 pSMB->TotalDataCount = pSMB->DataCount;
3978 pSMB->MaxParameterCount = cpu_to_le32(4);
3979 pSMB->MaxDataCount = cpu_to_le32(16384);
3980 pSMB->ParameterCount = cpu_to_le32(param_count);
3981 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3982 pSMB->TotalParameterCount = pSMB->ParameterCount;
3983 pSMB->DataOffset = cpu_to_le32(data_offset);
3984 pSMB->SetupCount = 0;
3985 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3986 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3987
3988 pSMB->Fid = fid; /* file handle always le */
3989 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003990 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003991
3992 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003993 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3994 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003995 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003996 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003997 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003998
3999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4001
Joe Perchesf96637b2013-05-04 22:12:25 -05004002 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4003 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004004 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004005 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004006 cifs_buf_release(pSMB);
4007
4008 if (rc == -EAGAIN)
4009 goto setCifsAclRetry;
4010
4011 return (rc);
4012}
4013
Jeff Layton79df1ba2010-12-06 12:52:08 -05004014#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004015
Steve French6b8edfe2005-08-23 20:26:03 -07004016/* Legacy Query Path Information call for lookup to old servers such
4017 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004018int
4019SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4020 const char *search_name, FILE_ALL_INFO *data,
4021 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004022{
Steve Frenchad7a2922008-02-07 23:25:02 +00004023 QUERY_INFORMATION_REQ *pSMB;
4024 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004025 int rc = 0;
4026 int bytes_returned;
4027 int name_len;
4028
Joe Perchesf96637b2013-05-04 22:12:25 -05004029 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004030QInfRetry:
4031 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004032 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004033 if (rc)
4034 return rc;
4035
4036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4037 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004038 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004039 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004040 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004041 name_len++; /* trailing null */
4042 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004043 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004044 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004045 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004046 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004047 }
4048 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004049 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004050 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004051 pSMB->ByteCount = cpu_to_le16(name_len);
4052
4053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004055 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004056 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004057 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004058 struct timespec ts;
4059 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004060
4061 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004062 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004063 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004064 ts.tv_nsec = 0;
4065 ts.tv_sec = time;
4066 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004067 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4068 data->LastWriteTime = data->ChangeTime;
4069 data->LastAccessTime = 0;
4070 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004071 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004072 data->EndOfFile = data->AllocationSize;
4073 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004074 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004075 } else
4076 rc = -EIO; /* bad buffer passed in */
4077
4078 cifs_buf_release(pSMB);
4079
4080 if (rc == -EAGAIN)
4081 goto QInfRetry;
4082
4083 return rc;
4084}
4085
Jeff Laytonbcd53572010-02-12 07:44:16 -05004086int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004087CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004088 u16 netfid, FILE_ALL_INFO *pFindData)
4089{
4090 struct smb_t2_qfi_req *pSMB = NULL;
4091 struct smb_t2_qfi_rsp *pSMBr = NULL;
4092 int rc = 0;
4093 int bytes_returned;
4094 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004095
Jeff Laytonbcd53572010-02-12 07:44:16 -05004096QFileInfoRetry:
4097 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4098 (void **) &pSMBr);
4099 if (rc)
4100 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004101
Jeff Laytonbcd53572010-02-12 07:44:16 -05004102 params = 2 /* level */ + 2 /* fid */;
4103 pSMB->t2.TotalDataCount = 0;
4104 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4105 /* BB find exact max data count below from sess structure BB */
4106 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4107 pSMB->t2.MaxSetupCount = 0;
4108 pSMB->t2.Reserved = 0;
4109 pSMB->t2.Flags = 0;
4110 pSMB->t2.Timeout = 0;
4111 pSMB->t2.Reserved2 = 0;
4112 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4113 Fid) - 4);
4114 pSMB->t2.DataCount = 0;
4115 pSMB->t2.DataOffset = 0;
4116 pSMB->t2.SetupCount = 1;
4117 pSMB->t2.Reserved3 = 0;
4118 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4119 byte_count = params + 1 /* pad */ ;
4120 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4121 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4122 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4123 pSMB->Pad = 0;
4124 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004125 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004126 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004127
4128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4130 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004131 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004132 } else { /* decode response */
4133 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4134
4135 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4136 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004137 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004138 rc = -EIO; /* bad smb */
4139 else if (pFindData) {
4140 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4141 memcpy((char *) pFindData,
4142 (char *) &pSMBr->hdr.Protocol +
4143 data_offset, sizeof(FILE_ALL_INFO));
4144 } else
4145 rc = -ENOMEM;
4146 }
4147 cifs_buf_release(pSMB);
4148 if (rc == -EAGAIN)
4149 goto QFileInfoRetry;
4150
4151 return rc;
4152}
Steve French6b8edfe2005-08-23 20:26:03 -07004153
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004155CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004156 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004157 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004158 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004160 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 TRANSACTION2_QPI_REQ *pSMB = NULL;
4162 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4163 int rc = 0;
4164 int bytes_returned;
4165 int name_len;
4166 __u16 params, byte_count;
4167
Joe Perchesf96637b2013-05-04 22:12:25 -05004168 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169QPathInfoRetry:
4170 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4171 (void **) &pSMBr);
4172 if (rc)
4173 return rc;
4174
4175 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4176 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004177 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004178 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 name_len++; /* trailing null */
4180 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004181 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004182 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004184 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 }
4186
Steve French50c2f752007-07-13 00:33:32 +00004187 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 pSMB->TotalDataCount = 0;
4189 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004190 /* BB find exact max SMB PDU from sess structure BB */
4191 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 pSMB->MaxSetupCount = 0;
4193 pSMB->Reserved = 0;
4194 pSMB->Flags = 0;
4195 pSMB->Timeout = 0;
4196 pSMB->Reserved2 = 0;
4197 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004198 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 pSMB->DataCount = 0;
4200 pSMB->DataOffset = 0;
4201 pSMB->SetupCount = 1;
4202 pSMB->Reserved3 = 0;
4203 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4204 byte_count = params + 1 /* pad */ ;
4205 pSMB->TotalParameterCount = cpu_to_le16(params);
4206 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004207 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004208 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4209 else
4210 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004212 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 pSMB->ByteCount = cpu_to_le16(byte_count);
4214
4215 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4216 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4217 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004218 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 } else { /* decode response */
4220 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4221
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004222 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4223 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004224 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004226 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004227 rc = -EIO; /* 24 or 26 expected but we do not read
4228 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004229 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004230 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004232
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004233 /*
4234 * On legacy responses we do not read the last field,
4235 * EAsize, fortunately since it varies by subdialect and
4236 * also note it differs on Set vs Get, ie two bytes or 4
4237 * bytes depending but we don't care here.
4238 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004239 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004240 size = sizeof(FILE_INFO_STANDARD);
4241 else
4242 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004243 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004244 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 } else
4246 rc = -ENOMEM;
4247 }
4248 cifs_buf_release(pSMB);
4249 if (rc == -EAGAIN)
4250 goto QPathInfoRetry;
4251
4252 return rc;
4253}
4254
4255int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004256CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004257 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4258{
4259 struct smb_t2_qfi_req *pSMB = NULL;
4260 struct smb_t2_qfi_rsp *pSMBr = NULL;
4261 int rc = 0;
4262 int bytes_returned;
4263 __u16 params, byte_count;
4264
4265UnixQFileInfoRetry:
4266 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4267 (void **) &pSMBr);
4268 if (rc)
4269 return rc;
4270
4271 params = 2 /* level */ + 2 /* fid */;
4272 pSMB->t2.TotalDataCount = 0;
4273 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4274 /* BB find exact max data count below from sess structure BB */
4275 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4276 pSMB->t2.MaxSetupCount = 0;
4277 pSMB->t2.Reserved = 0;
4278 pSMB->t2.Flags = 0;
4279 pSMB->t2.Timeout = 0;
4280 pSMB->t2.Reserved2 = 0;
4281 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4282 Fid) - 4);
4283 pSMB->t2.DataCount = 0;
4284 pSMB->t2.DataOffset = 0;
4285 pSMB->t2.SetupCount = 1;
4286 pSMB->t2.Reserved3 = 0;
4287 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4288 byte_count = params + 1 /* pad */ ;
4289 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4290 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4291 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4292 pSMB->Pad = 0;
4293 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004294 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004295 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004296
4297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4299 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004300 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004301 } else { /* decode response */
4302 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4303
Jeff Layton820a8032011-05-04 08:05:26 -04004304 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004305 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 -05004306 rc = -EIO; /* bad smb */
4307 } else {
4308 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4309 memcpy((char *) pFindData,
4310 (char *) &pSMBr->hdr.Protocol +
4311 data_offset,
4312 sizeof(FILE_UNIX_BASIC_INFO));
4313 }
4314 }
4315
4316 cifs_buf_release(pSMB);
4317 if (rc == -EAGAIN)
4318 goto UnixQFileInfoRetry;
4319
4320 return rc;
4321}
4322
4323int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004324CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004326 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004327 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328{
4329/* SMB_QUERY_FILE_UNIX_BASIC */
4330 TRANSACTION2_QPI_REQ *pSMB = NULL;
4331 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4332 int rc = 0;
4333 int bytes_returned = 0;
4334 int name_len;
4335 __u16 params, byte_count;
4336
Joe Perchesf96637b2013-05-04 22:12:25 -05004337 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338UnixQPathInfoRetry:
4339 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4340 (void **) &pSMBr);
4341 if (rc)
4342 return rc;
4343
4344 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4345 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004346 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4347 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 name_len++; /* trailing null */
4349 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004350 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 name_len = strnlen(searchName, PATH_MAX);
4352 name_len++; /* trailing null */
4353 strncpy(pSMB->FileName, searchName, name_len);
4354 }
4355
Steve French50c2f752007-07-13 00:33:32 +00004356 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 pSMB->TotalDataCount = 0;
4358 pSMB->MaxParameterCount = cpu_to_le16(2);
4359 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004360 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 pSMB->MaxSetupCount = 0;
4362 pSMB->Reserved = 0;
4363 pSMB->Flags = 0;
4364 pSMB->Timeout = 0;
4365 pSMB->Reserved2 = 0;
4366 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004367 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 pSMB->DataCount = 0;
4369 pSMB->DataOffset = 0;
4370 pSMB->SetupCount = 1;
4371 pSMB->Reserved3 = 0;
4372 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4373 byte_count = params + 1 /* pad */ ;
4374 pSMB->TotalParameterCount = cpu_to_le16(params);
4375 pSMB->ParameterCount = pSMB->TotalParameterCount;
4376 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4377 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004378 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 pSMB->ByteCount = cpu_to_le16(byte_count);
4380
4381 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4382 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4383 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004384 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 } else { /* decode response */
4386 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4387
Jeff Layton820a8032011-05-04 08:05:26 -04004388 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004389 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 -07004390 rc = -EIO; /* bad smb */
4391 } else {
4392 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4393 memcpy((char *) pFindData,
4394 (char *) &pSMBr->hdr.Protocol +
4395 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004396 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 }
4398 }
4399 cifs_buf_release(pSMB);
4400 if (rc == -EAGAIN)
4401 goto UnixQPathInfoRetry;
4402
4403 return rc;
4404}
4405
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406/* xid, tcon, searchName and codepage are input parms, rest are returned */
4407int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004408CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004409 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004410 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004411 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412{
4413/* level 257 SMB_ */
4414 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4415 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004416 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 int rc = 0;
4418 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004419 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004421 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
Joe Perchesf96637b2013-05-04 22:12:25 -05004423 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
4425findFirstRetry:
4426 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4427 (void **) &pSMBr);
4428 if (rc)
4429 return rc;
4430
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004431 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004432 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4435 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004436 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4437 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004438 /* We can not add the asterik earlier in case
4439 it got remapped to 0xF03A as if it were part of the
4440 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004442 if (msearch) {
4443 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4444 pSMB->FileName[name_len+1] = 0;
4445 pSMB->FileName[name_len+2] = '*';
4446 pSMB->FileName[name_len+3] = 0;
4447 name_len += 4; /* now the trailing null */
4448 /* null terminate just in case */
4449 pSMB->FileName[name_len] = 0;
4450 pSMB->FileName[name_len+1] = 0;
4451 name_len += 2;
4452 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 } else { /* BB add check for overrun of SMB buf BB */
4454 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004456 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 free buffer exit; BB */
4458 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004459 if (msearch) {
4460 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4461 pSMB->FileName[name_len+1] = '*';
4462 pSMB->FileName[name_len+2] = 0;
4463 name_len += 3;
4464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 }
4466
4467 params = 12 + name_len /* includes null */ ;
4468 pSMB->TotalDataCount = 0; /* no EAs */
4469 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004470 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 pSMB->MaxSetupCount = 0;
4472 pSMB->Reserved = 0;
4473 pSMB->Flags = 0;
4474 pSMB->Timeout = 0;
4475 pSMB->Reserved2 = 0;
4476 byte_count = params + 1 /* pad */ ;
4477 pSMB->TotalParameterCount = cpu_to_le16(params);
4478 pSMB->ParameterCount = pSMB->TotalParameterCount;
4479 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004480 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4481 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 pSMB->DataCount = 0;
4483 pSMB->DataOffset = 0;
4484 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4485 pSMB->Reserved3 = 0;
4486 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4487 pSMB->SearchAttributes =
4488 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4489 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004490 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004491 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4493
4494 /* BB what should we set StorageType to? Does it matter? BB */
4495 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004496 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 pSMB->ByteCount = cpu_to_le16(byte_count);
4498
4499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004501 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502
Steve French88274812006-03-09 22:21:45 +00004503 if (rc) {/* BB add logic to retry regular search if Unix search
4504 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004506 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004507
Steve French88274812006-03-09 22:21:45 +00004508 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
4510 /* BB eventually could optimize out free and realloc of buf */
4511 /* for this case */
4512 if (rc == -EAGAIN)
4513 goto findFirstRetry;
4514 } else { /* decode response */
4515 /* BB remember to free buffer if error BB */
4516 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004517 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004518 unsigned int lnoff;
4519
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004521 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 else
Steve French4b18f2a2008-04-29 00:06:05 +00004523 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
4525 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004526 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004527 psrch_inf->srch_entries_start =
4528 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4531 le16_to_cpu(pSMBr->t2.ParameterOffset));
4532
Steve French790fe572007-07-07 19:25:05 +00004533 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004534 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 else
Steve French4b18f2a2008-04-29 00:06:05 +00004536 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
Steve French50c2f752007-07-13 00:33:32 +00004538 psrch_inf->entries_in_buffer =
4539 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004540 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004542 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004543 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004544 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004545 psrch_inf->last_entry = NULL;
4546 return rc;
4547 }
4548
Steve French0752f152008-10-07 20:03:33 +00004549 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004550 lnoff;
4551
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004552 if (pnetfid)
4553 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 } else {
4555 cifs_buf_release(pSMB);
4556 }
4557 }
4558
4559 return rc;
4560}
4561
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004562int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4563 __u16 searchHandle, __u16 search_flags,
4564 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565{
4566 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4567 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004568 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 char *response_data;
4570 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004571 int bytes_returned;
4572 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 __u16 params, byte_count;
4574
Joe Perchesf96637b2013-05-04 22:12:25 -05004575 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576
Steve French4b18f2a2008-04-29 00:06:05 +00004577 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 return -ENOENT;
4579
4580 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4581 (void **) &pSMBr);
4582 if (rc)
4583 return rc;
4584
Steve French50c2f752007-07-13 00:33:32 +00004585 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 byte_count = 0;
4587 pSMB->TotalDataCount = 0; /* no EAs */
4588 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004589 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 pSMB->MaxSetupCount = 0;
4591 pSMB->Reserved = 0;
4592 pSMB->Flags = 0;
4593 pSMB->Timeout = 0;
4594 pSMB->Reserved2 = 0;
4595 pSMB->ParameterOffset = cpu_to_le16(
4596 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4597 pSMB->DataCount = 0;
4598 pSMB->DataOffset = 0;
4599 pSMB->SetupCount = 1;
4600 pSMB->Reserved3 = 0;
4601 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4602 pSMB->SearchHandle = searchHandle; /* always kept as le */
4603 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004604 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4606 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004607 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608
4609 name_len = psrch_inf->resume_name_len;
4610 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004611 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4613 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004614 /* 14 byte parm len above enough for 2 byte null terminator */
4615 pSMB->ResumeFileName[name_len] = 0;
4616 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 } else {
4618 rc = -EINVAL;
4619 goto FNext2_err_exit;
4620 }
4621 byte_count = params + 1 /* pad */ ;
4622 pSMB->TotalParameterCount = cpu_to_le16(params);
4623 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004624 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004626
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4628 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004629 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 if (rc) {
4631 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004632 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004633 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004634 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004636 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 } else { /* decode response */
4638 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004639
Steve French790fe572007-07-07 19:25:05 +00004640 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004641 unsigned int lnoff;
4642
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 /* BB fixme add lock for file (srch_info) struct here */
4644 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004645 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 else
Steve French4b18f2a2008-04-29 00:06:05 +00004647 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 response_data = (char *) &pSMBr->hdr.Protocol +
4649 le16_to_cpu(pSMBr->t2.ParameterOffset);
4650 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4651 response_data = (char *)&pSMBr->hdr.Protocol +
4652 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004653 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004654 cifs_small_buf_release(
4655 psrch_inf->ntwrk_buf_start);
4656 else
4657 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 psrch_inf->srch_entries_start = response_data;
4659 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004660 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004661 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004662 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 else
Steve French4b18f2a2008-04-29 00:06:05 +00004664 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004665 psrch_inf->entries_in_buffer =
4666 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 psrch_inf->index_of_last_entry +=
4668 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004669 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004670 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004671 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004672 psrch_inf->last_entry = NULL;
4673 return rc;
4674 } else
4675 psrch_inf->last_entry =
4676 psrch_inf->srch_entries_start + lnoff;
4677
Joe Perchesf96637b2013-05-04 22:12:25 -05004678/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4679 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
4681 /* BB fixme add unlock here */
4682 }
4683
4684 }
4685
4686 /* BB On error, should we leave previous search buf (and count and
4687 last entry fields) intact or free the previous one? */
4688
4689 /* Note: On -EAGAIN error only caller can retry on handle based calls
4690 since file handle passed in no longer valid */
4691FNext2_err_exit:
4692 if (rc != 0)
4693 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 return rc;
4695}
4696
4697int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004698CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004699 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700{
4701 int rc = 0;
4702 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703
Joe Perchesf96637b2013-05-04 22:12:25 -05004704 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4706
4707 /* no sense returning error if session restarted
4708 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004709 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 return 0;
4711 if (rc)
4712 return rc;
4713
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 pSMB->FileID = searchHandle;
4715 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004716 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004717 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004718 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004719 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004720
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004721 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
4723 /* Since session is dead, search handle closed on server already */
4724 if (rc == -EAGAIN)
4725 rc = 0;
4726
4727 return rc;
4728}
4729
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004731CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004732 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004733 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734{
4735 int rc = 0;
4736 TRANSACTION2_QPI_REQ *pSMB = NULL;
4737 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4738 int name_len, bytes_returned;
4739 __u16 params, byte_count;
4740
Joe Perchesf96637b2013-05-04 22:12:25 -05004741 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004742 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004743 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744
4745GetInodeNumberRetry:
4746 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004747 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 if (rc)
4749 return rc;
4750
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4752 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004753 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004754 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004755 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 name_len++; /* trailing null */
4757 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004758 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004759 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004761 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 }
4763
4764 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4765 pSMB->TotalDataCount = 0;
4766 pSMB->MaxParameterCount = cpu_to_le16(2);
4767 /* BB find exact max data count below from sess structure BB */
4768 pSMB->MaxDataCount = cpu_to_le16(4000);
4769 pSMB->MaxSetupCount = 0;
4770 pSMB->Reserved = 0;
4771 pSMB->Flags = 0;
4772 pSMB->Timeout = 0;
4773 pSMB->Reserved2 = 0;
4774 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004775 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 pSMB->DataCount = 0;
4777 pSMB->DataOffset = 0;
4778 pSMB->SetupCount = 1;
4779 pSMB->Reserved3 = 0;
4780 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4781 byte_count = params + 1 /* pad */ ;
4782 pSMB->TotalParameterCount = cpu_to_le16(params);
4783 pSMB->ParameterCount = pSMB->TotalParameterCount;
4784 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4785 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004786 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 pSMB->ByteCount = cpu_to_le16(byte_count);
4788
4789 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4790 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4791 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004792 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 } else {
4794 /* decode response */
4795 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004797 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 /* If rc should we check for EOPNOSUPP and
4799 disable the srvino flag? or in caller? */
4800 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004801 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4803 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004804 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004806 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004807 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 rc = -EIO;
4809 goto GetInodeNumOut;
4810 }
4811 pfinfo = (struct file_internal_info *)
4812 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004813 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 }
4815 }
4816GetInodeNumOut:
4817 cifs_buf_release(pSMB);
4818 if (rc == -EAGAIN)
4819 goto GetInodeNumberRetry;
4820 return rc;
4821}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822
4823int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004824CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004825 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004826 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004827 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828{
4829/* TRANS2_GET_DFS_REFERRAL */
4830 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4831 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 int rc = 0;
4833 int bytes_returned;
4834 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004836 *num_of_nodes = 0;
4837 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838
Joe Perchesf96637b2013-05-04 22:12:25 -05004839 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004840 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004842
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004844 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 (void **) &pSMBr);
4846 if (rc)
4847 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004848
4849 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004850 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004851 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004852 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004854 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004856 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
4859 if (ses->capabilities & CAP_UNICODE) {
4860 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4861 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004862 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004863 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004864 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 name_len++; /* trailing null */
4866 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004867 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004868 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004870 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 }
4872
Dan Carpenter65c3b202015-04-30 17:30:24 +03004873 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004874 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004875
Steve French50c2f752007-07-13 00:33:32 +00004876 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004877
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 params = 2 /* level */ + name_len /*includes null */ ;
4879 pSMB->TotalDataCount = 0;
4880 pSMB->DataCount = 0;
4881 pSMB->DataOffset = 0;
4882 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004883 /* BB find exact max SMB PDU from sess structure BB */
4884 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 pSMB->MaxSetupCount = 0;
4886 pSMB->Reserved = 0;
4887 pSMB->Flags = 0;
4888 pSMB->Timeout = 0;
4889 pSMB->Reserved2 = 0;
4890 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004891 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 pSMB->SetupCount = 1;
4893 pSMB->Reserved3 = 0;
4894 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4895 byte_count = params + 3 /* pad */ ;
4896 pSMB->ParameterCount = cpu_to_le16(params);
4897 pSMB->TotalParameterCount = pSMB->ParameterCount;
4898 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004899 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 pSMB->ByteCount = cpu_to_le16(byte_count);
4901
4902 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4903 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4904 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004905 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004906 goto GetDFSRefExit;
4907 }
4908 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004910 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004911 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004912 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004913 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004915
Joe Perchesf96637b2013-05-04 22:12:25 -05004916 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4917 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004918
4919 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004920 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4921 le16_to_cpu(pSMBr->t2.DataCount),
4922 num_of_nodes, target_nodes, nls_codepage,
4923 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004924 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004925
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004927 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928
4929 if (rc == -EAGAIN)
4930 goto getDFSRetry;
4931
4932 return rc;
4933}
4934
Steve French20962432005-09-21 22:05:57 -07004935/* Query File System Info such as free space to old servers such as Win 9x */
4936int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004937SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4938 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004939{
4940/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4941 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4942 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4943 FILE_SYSTEM_ALLOC_INFO *response_data;
4944 int rc = 0;
4945 int bytes_returned = 0;
4946 __u16 params, byte_count;
4947
Joe Perchesf96637b2013-05-04 22:12:25 -05004948 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004949oldQFSInfoRetry:
4950 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4951 (void **) &pSMBr);
4952 if (rc)
4953 return rc;
Steve French20962432005-09-21 22:05:57 -07004954
4955 params = 2; /* level */
4956 pSMB->TotalDataCount = 0;
4957 pSMB->MaxParameterCount = cpu_to_le16(2);
4958 pSMB->MaxDataCount = cpu_to_le16(1000);
4959 pSMB->MaxSetupCount = 0;
4960 pSMB->Reserved = 0;
4961 pSMB->Flags = 0;
4962 pSMB->Timeout = 0;
4963 pSMB->Reserved2 = 0;
4964 byte_count = params + 1 /* pad */ ;
4965 pSMB->TotalParameterCount = cpu_to_le16(params);
4966 pSMB->ParameterCount = pSMB->TotalParameterCount;
4967 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4968 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4969 pSMB->DataCount = 0;
4970 pSMB->DataOffset = 0;
4971 pSMB->SetupCount = 1;
4972 pSMB->Reserved3 = 0;
4973 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4974 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004975 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004976 pSMB->ByteCount = cpu_to_le16(byte_count);
4977
4978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4980 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004981 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004982 } else { /* decode response */
4983 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4984
Jeff Layton820a8032011-05-04 08:05:26 -04004985 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004986 rc = -EIO; /* bad smb */
4987 else {
4988 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004989 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004990 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004991
Steve French50c2f752007-07-13 00:33:32 +00004992 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004993 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4994 FSData->f_bsize =
4995 le16_to_cpu(response_data->BytesPerSector) *
4996 le32_to_cpu(response_data->
4997 SectorsPerAllocationUnit);
4998 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004999 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005000 FSData->f_bfree = FSData->f_bavail =
5001 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005002 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5003 (unsigned long long)FSData->f_blocks,
5004 (unsigned long long)FSData->f_bfree,
5005 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005006 }
5007 }
5008 cifs_buf_release(pSMB);
5009
5010 if (rc == -EAGAIN)
5011 goto oldQFSInfoRetry;
5012
5013 return rc;
5014}
5015
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005017CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5018 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019{
5020/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5021 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5022 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5023 FILE_SYSTEM_INFO *response_data;
5024 int rc = 0;
5025 int bytes_returned = 0;
5026 __u16 params, byte_count;
5027
Joe Perchesf96637b2013-05-04 22:12:25 -05005028 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029QFSInfoRetry:
5030 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5031 (void **) &pSMBr);
5032 if (rc)
5033 return rc;
5034
5035 params = 2; /* level */
5036 pSMB->TotalDataCount = 0;
5037 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005038 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 pSMB->MaxSetupCount = 0;
5040 pSMB->Reserved = 0;
5041 pSMB->Flags = 0;
5042 pSMB->Timeout = 0;
5043 pSMB->Reserved2 = 0;
5044 byte_count = params + 1 /* pad */ ;
5045 pSMB->TotalParameterCount = cpu_to_le16(params);
5046 pSMB->ParameterCount = pSMB->TotalParameterCount;
5047 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005048 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 pSMB->DataCount = 0;
5050 pSMB->DataOffset = 0;
5051 pSMB->SetupCount = 1;
5052 pSMB->Reserved3 = 0;
5053 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5054 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005055 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 pSMB->ByteCount = cpu_to_le16(byte_count);
5057
5058 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5059 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5060 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005061 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005063 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064
Jeff Layton820a8032011-05-04 08:05:26 -04005065 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 rc = -EIO; /* bad smb */
5067 else {
5068 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
5070 response_data =
5071 (FILE_SYSTEM_INFO
5072 *) (((char *) &pSMBr->hdr.Protocol) +
5073 data_offset);
5074 FSData->f_bsize =
5075 le32_to_cpu(response_data->BytesPerSector) *
5076 le32_to_cpu(response_data->
5077 SectorsPerAllocationUnit);
5078 FSData->f_blocks =
5079 le64_to_cpu(response_data->TotalAllocationUnits);
5080 FSData->f_bfree = FSData->f_bavail =
5081 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005082 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5083 (unsigned long long)FSData->f_blocks,
5084 (unsigned long long)FSData->f_bfree,
5085 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 }
5087 }
5088 cifs_buf_release(pSMB);
5089
5090 if (rc == -EAGAIN)
5091 goto QFSInfoRetry;
5092
5093 return rc;
5094}
5095
5096int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005097CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098{
5099/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5100 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5101 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5102 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5103 int rc = 0;
5104 int bytes_returned = 0;
5105 __u16 params, byte_count;
5106
Joe Perchesf96637b2013-05-04 22:12:25 -05005107 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108QFSAttributeRetry:
5109 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5110 (void **) &pSMBr);
5111 if (rc)
5112 return rc;
5113
5114 params = 2; /* level */
5115 pSMB->TotalDataCount = 0;
5116 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005117 /* BB find exact max SMB PDU from sess structure BB */
5118 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 pSMB->MaxSetupCount = 0;
5120 pSMB->Reserved = 0;
5121 pSMB->Flags = 0;
5122 pSMB->Timeout = 0;
5123 pSMB->Reserved2 = 0;
5124 byte_count = params + 1 /* pad */ ;
5125 pSMB->TotalParameterCount = cpu_to_le16(params);
5126 pSMB->ParameterCount = pSMB->TotalParameterCount;
5127 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005128 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 pSMB->DataCount = 0;
5130 pSMB->DataOffset = 0;
5131 pSMB->SetupCount = 1;
5132 pSMB->Reserved3 = 0;
5133 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5134 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005135 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 pSMB->ByteCount = cpu_to_le16(byte_count);
5137
5138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5139 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5140 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005141 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 } else { /* decode response */
5143 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5144
Jeff Layton820a8032011-05-04 08:05:26 -04005145 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005146 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 rc = -EIO; /* bad smb */
5148 } else {
5149 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5150 response_data =
5151 (FILE_SYSTEM_ATTRIBUTE_INFO
5152 *) (((char *) &pSMBr->hdr.Protocol) +
5153 data_offset);
5154 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005155 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 }
5157 }
5158 cifs_buf_release(pSMB);
5159
5160 if (rc == -EAGAIN)
5161 goto QFSAttributeRetry;
5162
5163 return rc;
5164}
5165
5166int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005167CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168{
5169/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5170 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5171 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5172 FILE_SYSTEM_DEVICE_INFO *response_data;
5173 int rc = 0;
5174 int bytes_returned = 0;
5175 __u16 params, byte_count;
5176
Joe Perchesf96637b2013-05-04 22:12:25 -05005177 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178QFSDeviceRetry:
5179 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5180 (void **) &pSMBr);
5181 if (rc)
5182 return rc;
5183
5184 params = 2; /* level */
5185 pSMB->TotalDataCount = 0;
5186 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005187 /* BB find exact max SMB PDU from sess structure BB */
5188 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 pSMB->MaxSetupCount = 0;
5190 pSMB->Reserved = 0;
5191 pSMB->Flags = 0;
5192 pSMB->Timeout = 0;
5193 pSMB->Reserved2 = 0;
5194 byte_count = params + 1 /* pad */ ;
5195 pSMB->TotalParameterCount = cpu_to_le16(params);
5196 pSMB->ParameterCount = pSMB->TotalParameterCount;
5197 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005198 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199
5200 pSMB->DataCount = 0;
5201 pSMB->DataOffset = 0;
5202 pSMB->SetupCount = 1;
5203 pSMB->Reserved3 = 0;
5204 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5205 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005206 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pSMB->ByteCount = cpu_to_le16(byte_count);
5208
5209 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5210 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5211 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005212 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 } else { /* decode response */
5214 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5215
Jeff Layton820a8032011-05-04 08:05:26 -04005216 if (rc || get_bcc(&pSMBr->hdr) <
5217 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 rc = -EIO; /* bad smb */
5219 else {
5220 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5221 response_data =
Steve French737b7582005-04-28 22:41:06 -07005222 (FILE_SYSTEM_DEVICE_INFO *)
5223 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 data_offset);
5225 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005226 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 }
5228 }
5229 cifs_buf_release(pSMB);
5230
5231 if (rc == -EAGAIN)
5232 goto QFSDeviceRetry;
5233
5234 return rc;
5235}
5236
5237int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005238CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239{
5240/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5241 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5242 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5243 FILE_SYSTEM_UNIX_INFO *response_data;
5244 int rc = 0;
5245 int bytes_returned = 0;
5246 __u16 params, byte_count;
5247
Joe Perchesf96637b2013-05-04 22:12:25 -05005248 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005250 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5251 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 if (rc)
5253 return rc;
5254
5255 params = 2; /* level */
5256 pSMB->TotalDataCount = 0;
5257 pSMB->DataCount = 0;
5258 pSMB->DataOffset = 0;
5259 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005260 /* BB find exact max SMB PDU from sess structure BB */
5261 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 pSMB->MaxSetupCount = 0;
5263 pSMB->Reserved = 0;
5264 pSMB->Flags = 0;
5265 pSMB->Timeout = 0;
5266 pSMB->Reserved2 = 0;
5267 byte_count = params + 1 /* pad */ ;
5268 pSMB->ParameterCount = cpu_to_le16(params);
5269 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005270 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5271 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 pSMB->SetupCount = 1;
5273 pSMB->Reserved3 = 0;
5274 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5275 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005276 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 pSMB->ByteCount = cpu_to_le16(byte_count);
5278
5279 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5280 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5281 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005282 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 } else { /* decode response */
5284 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5285
Jeff Layton820a8032011-05-04 08:05:26 -04005286 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 rc = -EIO; /* bad smb */
5288 } else {
5289 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5290 response_data =
5291 (FILE_SYSTEM_UNIX_INFO
5292 *) (((char *) &pSMBr->hdr.Protocol) +
5293 data_offset);
5294 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005295 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 }
5297 }
5298 cifs_buf_release(pSMB);
5299
5300 if (rc == -EAGAIN)
5301 goto QFSUnixRetry;
5302
5303
5304 return rc;
5305}
5306
Jeremy Allisonac670552005-06-22 17:26:35 -07005307int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005308CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005309{
5310/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5311 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5312 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5313 int rc = 0;
5314 int bytes_returned = 0;
5315 __u16 params, param_offset, offset, byte_count;
5316
Joe Perchesf96637b2013-05-04 22:12:25 -05005317 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005318SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005319 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005320 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5321 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005322 if (rc)
5323 return rc;
5324
5325 params = 4; /* 2 bytes zero followed by info level. */
5326 pSMB->MaxSetupCount = 0;
5327 pSMB->Reserved = 0;
5328 pSMB->Flags = 0;
5329 pSMB->Timeout = 0;
5330 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005331 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5332 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005333 offset = param_offset + params;
5334
5335 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005336 /* BB find exact max SMB PDU from sess structure BB */
5337 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005338 pSMB->SetupCount = 1;
5339 pSMB->Reserved3 = 0;
5340 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5341 byte_count = 1 /* pad */ + params + 12;
5342
5343 pSMB->DataCount = cpu_to_le16(12);
5344 pSMB->ParameterCount = cpu_to_le16(params);
5345 pSMB->TotalDataCount = pSMB->DataCount;
5346 pSMB->TotalParameterCount = pSMB->ParameterCount;
5347 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5348 pSMB->DataOffset = cpu_to_le16(offset);
5349
5350 /* Params. */
5351 pSMB->FileNum = 0;
5352 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5353
5354 /* Data. */
5355 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5356 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5357 pSMB->ClientUnixCap = cpu_to_le64(cap);
5358
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005359 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005360 pSMB->ByteCount = cpu_to_le16(byte_count);
5361
5362 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5363 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5364 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005365 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005366 } else { /* decode response */
5367 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005368 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005369 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005370 }
5371 cifs_buf_release(pSMB);
5372
5373 if (rc == -EAGAIN)
5374 goto SETFSUnixRetry;
5375
5376 return rc;
5377}
5378
5379
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380
5381int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005382CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005383 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384{
5385/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5386 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5387 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5388 FILE_SYSTEM_POSIX_INFO *response_data;
5389 int rc = 0;
5390 int bytes_returned = 0;
5391 __u16 params, byte_count;
5392
Joe Perchesf96637b2013-05-04 22:12:25 -05005393 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394QFSPosixRetry:
5395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5396 (void **) &pSMBr);
5397 if (rc)
5398 return rc;
5399
5400 params = 2; /* level */
5401 pSMB->TotalDataCount = 0;
5402 pSMB->DataCount = 0;
5403 pSMB->DataOffset = 0;
5404 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005405 /* BB find exact max SMB PDU from sess structure BB */
5406 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 pSMB->MaxSetupCount = 0;
5408 pSMB->Reserved = 0;
5409 pSMB->Flags = 0;
5410 pSMB->Timeout = 0;
5411 pSMB->Reserved2 = 0;
5412 byte_count = params + 1 /* pad */ ;
5413 pSMB->ParameterCount = cpu_to_le16(params);
5414 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005415 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5416 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 pSMB->SetupCount = 1;
5418 pSMB->Reserved3 = 0;
5419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5420 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005421 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 pSMB->ByteCount = cpu_to_le16(byte_count);
5423
5424 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5426 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005427 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 } else { /* decode response */
5429 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5430
Jeff Layton820a8032011-05-04 08:05:26 -04005431 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 rc = -EIO; /* bad smb */
5433 } else {
5434 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5435 response_data =
5436 (FILE_SYSTEM_POSIX_INFO
5437 *) (((char *) &pSMBr->hdr.Protocol) +
5438 data_offset);
5439 FSData->f_bsize =
5440 le32_to_cpu(response_data->BlockSize);
5441 FSData->f_blocks =
5442 le64_to_cpu(response_data->TotalBlocks);
5443 FSData->f_bfree =
5444 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005445 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 FSData->f_bavail = FSData->f_bfree;
5447 } else {
5448 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005449 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 }
Steve French790fe572007-07-07 19:25:05 +00005451 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005453 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005454 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005456 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 }
5458 }
5459 cifs_buf_release(pSMB);
5460
5461 if (rc == -EAGAIN)
5462 goto QFSPosixRetry;
5463
5464 return rc;
5465}
5466
5467
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005468/*
5469 * We can not use write of zero bytes trick to set file size due to need for
5470 * large file support. Also note that this SetPathInfo is preferred to
5471 * SetFileInfo based method in next routine which is only needed to work around
5472 * a sharing violation bugin Samba which this routine can run into.
5473 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005475CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005476 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5477 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478{
5479 struct smb_com_transaction2_spi_req *pSMB = NULL;
5480 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5481 struct file_end_of_file_info *parm_data;
5482 int name_len;
5483 int rc = 0;
5484 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005485 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005486
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 __u16 params, byte_count, data_count, param_offset, offset;
5488
Joe Perchesf96637b2013-05-04 22:12:25 -05005489 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490SetEOFRetry:
5491 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5492 (void **) &pSMBr);
5493 if (rc)
5494 return rc;
5495
5496 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5497 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005498 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5499 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 name_len++; /* trailing null */
5501 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005502 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005503 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005505 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 }
5507 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005508 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005510 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 pSMB->MaxSetupCount = 0;
5512 pSMB->Reserved = 0;
5513 pSMB->Flags = 0;
5514 pSMB->Timeout = 0;
5515 pSMB->Reserved2 = 0;
5516 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005517 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005519 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005520 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5521 pSMB->InformationLevel =
5522 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5523 else
5524 pSMB->InformationLevel =
5525 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5526 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5528 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005529 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 else
5531 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005532 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 }
5534
5535 parm_data =
5536 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5537 offset);
5538 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5539 pSMB->DataOffset = cpu_to_le16(offset);
5540 pSMB->SetupCount = 1;
5541 pSMB->Reserved3 = 0;
5542 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5543 byte_count = 3 /* pad */ + params + data_count;
5544 pSMB->DataCount = cpu_to_le16(data_count);
5545 pSMB->TotalDataCount = pSMB->DataCount;
5546 pSMB->ParameterCount = cpu_to_le16(params);
5547 pSMB->TotalParameterCount = pSMB->ParameterCount;
5548 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005549 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 parm_data->FileSize = cpu_to_le64(size);
5551 pSMB->ByteCount = cpu_to_le16(byte_count);
5552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005554 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005555 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556
5557 cifs_buf_release(pSMB);
5558
5559 if (rc == -EAGAIN)
5560 goto SetEOFRetry;
5561
5562 return rc;
5563}
5564
5565int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005566CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5567 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568{
5569 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 struct file_end_of_file_info *parm_data;
5571 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 __u16 params, param_offset, offset, byte_count, count;
5573
Joe Perchesf96637b2013-05-04 22:12:25 -05005574 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5575 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005576 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5577
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 if (rc)
5579 return rc;
5580
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005581 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5582 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005583
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 params = 6;
5585 pSMB->MaxSetupCount = 0;
5586 pSMB->Reserved = 0;
5587 pSMB->Flags = 0;
5588 pSMB->Timeout = 0;
5589 pSMB->Reserved2 = 0;
5590 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5591 offset = param_offset + params;
5592
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 count = sizeof(struct file_end_of_file_info);
5594 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005595 /* BB find exact max SMB PDU from sess structure BB */
5596 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 pSMB->SetupCount = 1;
5598 pSMB->Reserved3 = 0;
5599 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5600 byte_count = 3 /* pad */ + params + count;
5601 pSMB->DataCount = cpu_to_le16(count);
5602 pSMB->ParameterCount = cpu_to_le16(params);
5603 pSMB->TotalDataCount = pSMB->DataCount;
5604 pSMB->TotalParameterCount = pSMB->ParameterCount;
5605 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5606 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005607 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5608 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 pSMB->DataOffset = cpu_to_le16(offset);
5610 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005611 pSMB->Fid = cfile->fid.netfid;
5612 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5614 pSMB->InformationLevel =
5615 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5616 else
5617 pSMB->InformationLevel =
5618 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005619 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5621 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005622 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 else
5624 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005625 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 }
5627 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005628 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005630 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005631 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005633 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5634 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 }
5636
Steve French50c2f752007-07-13 00:33:32 +00005637 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 since file handle passed in no longer valid */
5639
5640 return rc;
5641}
5642
Steve French50c2f752007-07-13 00:33:32 +00005643/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 an open handle, rather than by pathname - this is awkward due to
5645 potential access conflicts on the open, but it is unavoidable for these
5646 old servers since the only other choice is to go from 100 nanosecond DCE
5647 time and resort to the original setpathinfo level which takes the ancient
5648 DOS time format with 2 second granularity */
5649int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005650CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005651 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652{
5653 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 char *data_offset;
5655 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 __u16 params, param_offset, offset, byte_count, count;
5657
Joe Perchesf96637b2013-05-04 22:12:25 -05005658 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005659 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5660
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 if (rc)
5662 return rc;
5663
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005664 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5665 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005666
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 params = 6;
5668 pSMB->MaxSetupCount = 0;
5669 pSMB->Reserved = 0;
5670 pSMB->Flags = 0;
5671 pSMB->Timeout = 0;
5672 pSMB->Reserved2 = 0;
5673 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5674 offset = param_offset + params;
5675
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005676 data_offset = (char *)pSMB +
5677 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678
Steve French26f57362007-08-30 22:09:15 +00005679 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005681 /* BB find max SMB PDU from sess */
5682 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 pSMB->SetupCount = 1;
5684 pSMB->Reserved3 = 0;
5685 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5686 byte_count = 3 /* pad */ + params + count;
5687 pSMB->DataCount = cpu_to_le16(count);
5688 pSMB->ParameterCount = cpu_to_le16(params);
5689 pSMB->TotalDataCount = pSMB->DataCount;
5690 pSMB->TotalParameterCount = pSMB->ParameterCount;
5691 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5692 pSMB->DataOffset = cpu_to_le16(offset);
5693 pSMB->Fid = fid;
5694 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5695 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5696 else
5697 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5698 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005699 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005701 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005702 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005703 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005704 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005705 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5706 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
Steve French50c2f752007-07-13 00:33:32 +00005708 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 since file handle passed in no longer valid */
5710
5711 return rc;
5712}
5713
Jeff Layton6d22f092008-09-23 11:48:35 -04005714int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005715CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005716 bool delete_file, __u16 fid, __u32 pid_of_opener)
5717{
5718 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5719 char *data_offset;
5720 int rc = 0;
5721 __u16 params, param_offset, offset, byte_count, count;
5722
Joe Perchesf96637b2013-05-04 22:12:25 -05005723 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005724 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5725
5726 if (rc)
5727 return rc;
5728
5729 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5730 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5731
5732 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
5741 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5742
5743 count = 1;
5744 pSMB->MaxParameterCount = cpu_to_le16(2);
5745 /* BB find max SMB PDU from sess */
5746 pSMB->MaxDataCount = cpu_to_le16(1000);
5747 pSMB->SetupCount = 1;
5748 pSMB->Reserved3 = 0;
5749 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5750 byte_count = 3 /* pad */ + params + count;
5751 pSMB->DataCount = cpu_to_le16(count);
5752 pSMB->ParameterCount = cpu_to_le16(params);
5753 pSMB->TotalDataCount = pSMB->DataCount;
5754 pSMB->TotalParameterCount = pSMB->ParameterCount;
5755 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5756 pSMB->DataOffset = cpu_to_le16(offset);
5757 pSMB->Fid = fid;
5758 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5759 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005760 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005761 pSMB->ByteCount = cpu_to_le16(byte_count);
5762 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005763 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005764 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005765 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005766 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005767
5768 return rc;
5769}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
5771int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005772CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005773 const char *fileName, const FILE_BASIC_INFO *data,
5774 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775{
5776 TRANSACTION2_SPI_REQ *pSMB = NULL;
5777 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5778 int name_len;
5779 int rc = 0;
5780 int bytes_returned = 0;
5781 char *data_offset;
5782 __u16 params, param_offset, offset, byte_count, count;
5783
Joe Perchesf96637b2013-05-04 22:12:25 -05005784 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785
5786SetTimesRetry:
5787 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5788 (void **) &pSMBr);
5789 if (rc)
5790 return rc;
5791
5792 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5793 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005794 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5795 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796 name_len++; /* trailing null */
5797 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005798 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799 name_len = strnlen(fileName, PATH_MAX);
5800 name_len++; /* trailing null */
5801 strncpy(pSMB->FileName, fileName, name_len);
5802 }
5803
5804 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005805 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005807 /* BB find max SMB PDU from sess structure BB */
5808 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 pSMB->MaxSetupCount = 0;
5810 pSMB->Reserved = 0;
5811 pSMB->Flags = 0;
5812 pSMB->Timeout = 0;
5813 pSMB->Reserved2 = 0;
5814 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005815 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816 offset = param_offset + params;
5817 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5818 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5819 pSMB->DataOffset = cpu_to_le16(offset);
5820 pSMB->SetupCount = 1;
5821 pSMB->Reserved3 = 0;
5822 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5823 byte_count = 3 /* pad */ + params + count;
5824
5825 pSMB->DataCount = cpu_to_le16(count);
5826 pSMB->ParameterCount = cpu_to_le16(params);
5827 pSMB->TotalDataCount = pSMB->DataCount;
5828 pSMB->TotalParameterCount = pSMB->ParameterCount;
5829 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5830 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5831 else
5832 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5833 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005834 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005835 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 pSMB->ByteCount = cpu_to_le16(byte_count);
5837 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5838 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005839 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005840 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841
5842 cifs_buf_release(pSMB);
5843
5844 if (rc == -EAGAIN)
5845 goto SetTimesRetry;
5846
5847 return rc;
5848}
5849
5850/* Can not be used to set time stamps yet (due to old DOS time format) */
5851/* Can be used to set attributes */
5852#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5853 handling it anyway and NT4 was what we thought it would be needed for
5854 Do not delete it until we prove whether needed for Win9x though */
5855int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005856CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857 __u16 dos_attrs, const struct nls_table *nls_codepage)
5858{
5859 SETATTR_REQ *pSMB = NULL;
5860 SETATTR_RSP *pSMBr = NULL;
5861 int rc = 0;
5862 int bytes_returned;
5863 int name_len;
5864
Joe Perchesf96637b2013-05-04 22:12:25 -05005865 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866
5867SetAttrLgcyRetry:
5868 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5869 (void **) &pSMBr);
5870 if (rc)
5871 return rc;
5872
5873 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5874 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005875 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5876 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 name_len++; /* trailing null */
5878 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005879 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 name_len = strnlen(fileName, PATH_MAX);
5881 name_len++; /* trailing null */
5882 strncpy(pSMB->fileName, fileName, name_len);
5883 }
5884 pSMB->attr = cpu_to_le16(dos_attrs);
5885 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005886 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5888 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5889 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005890 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005891 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892
5893 cifs_buf_release(pSMB);
5894
5895 if (rc == -EAGAIN)
5896 goto SetAttrLgcyRetry;
5897
5898 return rc;
5899}
5900#endif /* temporarily unneeded SetAttr legacy function */
5901
Jeff Layton654cf142009-07-09 20:02:49 -04005902static void
5903cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5904 const struct cifs_unix_set_info_args *args)
5905{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005906 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005907 u64 mode = args->mode;
5908
Eric W. Biederman49418b22013-02-06 00:57:56 -08005909 if (uid_valid(args->uid))
5910 uid = from_kuid(&init_user_ns, args->uid);
5911 if (gid_valid(args->gid))
5912 gid = from_kgid(&init_user_ns, args->gid);
5913
Jeff Layton654cf142009-07-09 20:02:49 -04005914 /*
5915 * Samba server ignores set of file size to zero due to bugs in some
5916 * older clients, but we should be precise - we use SetFileSize to
5917 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005918 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005919 * zero instead of -1 here
5920 */
5921 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5922 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5923 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5924 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5925 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005926 data_offset->Uid = cpu_to_le64(uid);
5927 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005928 /* better to leave device as zero when it is */
5929 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5930 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5931 data_offset->Permissions = cpu_to_le64(mode);
5932
5933 if (S_ISREG(mode))
5934 data_offset->Type = cpu_to_le32(UNIX_FILE);
5935 else if (S_ISDIR(mode))
5936 data_offset->Type = cpu_to_le32(UNIX_DIR);
5937 else if (S_ISLNK(mode))
5938 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5939 else if (S_ISCHR(mode))
5940 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5941 else if (S_ISBLK(mode))
5942 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5943 else if (S_ISFIFO(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5945 else if (S_ISSOCK(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5947}
5948
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005950CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005951 const struct cifs_unix_set_info_args *args,
5952 u16 fid, u32 pid_of_opener)
5953{
5954 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005955 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005956 int rc = 0;
5957 u16 params, param_offset, offset, byte_count, count;
5958
Joe Perchesf96637b2013-05-04 22:12:25 -05005959 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005960 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5961
5962 if (rc)
5963 return rc;
5964
5965 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5966 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5967
5968 params = 6;
5969 pSMB->MaxSetupCount = 0;
5970 pSMB->Reserved = 0;
5971 pSMB->Flags = 0;
5972 pSMB->Timeout = 0;
5973 pSMB->Reserved2 = 0;
5974 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5975 offset = param_offset + params;
5976
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005977 data_offset = (char *)pSMB +
5978 offsetof(struct smb_hdr, Protocol) + offset;
5979
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005980 count = sizeof(FILE_UNIX_BASIC_INFO);
5981
5982 pSMB->MaxParameterCount = cpu_to_le16(2);
5983 /* BB find max SMB PDU from sess */
5984 pSMB->MaxDataCount = cpu_to_le16(1000);
5985 pSMB->SetupCount = 1;
5986 pSMB->Reserved3 = 0;
5987 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5988 byte_count = 3 /* pad */ + params + count;
5989 pSMB->DataCount = cpu_to_le16(count);
5990 pSMB->ParameterCount = cpu_to_le16(params);
5991 pSMB->TotalDataCount = pSMB->DataCount;
5992 pSMB->TotalParameterCount = pSMB->ParameterCount;
5993 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5994 pSMB->DataOffset = cpu_to_le16(offset);
5995 pSMB->Fid = fid;
5996 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5997 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005998 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005999 pSMB->ByteCount = cpu_to_le16(byte_count);
6000
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006001 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006002
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006003 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006004 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006005 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006006 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6007 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006008
6009 /* Note: On -EAGAIN error only caller can retry on handle based calls
6010 since file handle passed in no longer valid */
6011
6012 return rc;
6013}
6014
6015int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006016CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006017 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006018 const struct cifs_unix_set_info_args *args,
6019 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020{
6021 TRANSACTION2_SPI_REQ *pSMB = NULL;
6022 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6023 int name_len;
6024 int rc = 0;
6025 int bytes_returned = 0;
6026 FILE_UNIX_BASIC_INFO *data_offset;
6027 __u16 params, param_offset, offset, count, byte_count;
6028
Joe Perchesf96637b2013-05-04 22:12:25 -05006029 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030setPermsRetry:
6031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6032 (void **) &pSMBr);
6033 if (rc)
6034 return rc;
6035
6036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6037 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006038 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006039 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040 name_len++; /* trailing null */
6041 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006042 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006043 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006045 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 }
6047
6048 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006049 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006051 /* BB find max SMB PDU from sess structure BB */
6052 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053 pSMB->MaxSetupCount = 0;
6054 pSMB->Reserved = 0;
6055 pSMB->Flags = 0;
6056 pSMB->Timeout = 0;
6057 pSMB->Reserved2 = 0;
6058 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006059 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 offset = param_offset + params;
6061 data_offset =
6062 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6063 offset);
6064 memset(data_offset, 0, count);
6065 pSMB->DataOffset = cpu_to_le16(offset);
6066 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6067 pSMB->SetupCount = 1;
6068 pSMB->Reserved3 = 0;
6069 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6070 byte_count = 3 /* pad */ + params + count;
6071 pSMB->ParameterCount = cpu_to_le16(params);
6072 pSMB->DataCount = cpu_to_le16(count);
6073 pSMB->TotalParameterCount = pSMB->ParameterCount;
6074 pSMB->TotalDataCount = pSMB->DataCount;
6075 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6076 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006077 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006078
Jeff Layton654cf142009-07-09 20:02:49 -04006079 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080
6081 pSMB->ByteCount = cpu_to_le16(byte_count);
6082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006084 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006085 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
Steve French0d817bc2008-05-22 02:02:03 +00006087 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 if (rc == -EAGAIN)
6089 goto setPermsRetry;
6090 return rc;
6091}
6092
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006094/*
6095 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6096 * function used by listxattr and getxattr type calls. When ea_name is set,
6097 * it looks for that attribute name and stuffs that value into the EAData
6098 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6099 * buffer. In both cases, the return value is either the length of the
6100 * resulting data or a negative error code. If EAData is a NULL pointer then
6101 * the data isn't copied to it, but the length is returned.
6102 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006104CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006105 const unsigned char *searchName, const unsigned char *ea_name,
6106 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006107 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108{
6109 /* BB assumes one setup word */
6110 TRANSACTION2_QPI_REQ *pSMB = NULL;
6111 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006112 int remap = cifs_remap(cifs_sb);
6113 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114 int rc = 0;
6115 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006116 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006117 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006118 struct fea *temp_fea;
6119 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006120 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006121 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006122 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123
Joe Perchesf96637b2013-05-04 22:12:25 -05006124 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125QAllEAsRetry:
6126 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6127 (void **) &pSMBr);
6128 if (rc)
6129 return rc;
6130
6131 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006132 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006133 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6134 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006135 list_len++; /* trailing null */
6136 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006138 list_len = strnlen(searchName, PATH_MAX);
6139 list_len++; /* trailing null */
6140 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 }
6142
Jeff Layton6e462b92010-02-10 16:18:26 -05006143 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144 pSMB->TotalDataCount = 0;
6145 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006146 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006147 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 pSMB->MaxSetupCount = 0;
6149 pSMB->Reserved = 0;
6150 pSMB->Flags = 0;
6151 pSMB->Timeout = 0;
6152 pSMB->Reserved2 = 0;
6153 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006154 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 pSMB->DataCount = 0;
6156 pSMB->DataOffset = 0;
6157 pSMB->SetupCount = 1;
6158 pSMB->Reserved3 = 0;
6159 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6160 byte_count = params + 1 /* pad */ ;
6161 pSMB->TotalParameterCount = cpu_to_le16(params);
6162 pSMB->ParameterCount = pSMB->TotalParameterCount;
6163 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6164 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006165 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166 pSMB->ByteCount = cpu_to_le16(byte_count);
6167
6168 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6169 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6170 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006171 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006172 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006174
6175
6176 /* BB also check enough total bytes returned */
6177 /* BB we need to improve the validity checking
6178 of these trans2 responses */
6179
6180 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006181 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006182 rc = -EIO; /* bad smb */
6183 goto QAllEAsOut;
6184 }
6185
6186 /* check that length of list is not more than bcc */
6187 /* check that each entry does not go beyond length
6188 of list */
6189 /* check that each element of each entry does not
6190 go beyond end of list */
6191 /* validate_trans2_offsets() */
6192 /* BB check if start of smb + data_offset > &bcc+ bcc */
6193
6194 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6195 ea_response_data = (struct fealist *)
6196 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6197
Jeff Layton6e462b92010-02-10 16:18:26 -05006198 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006199 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006200 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006201 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006202 /* didn't find the named attribute */
6203 if (ea_name)
6204 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006205 goto QAllEAsOut;
6206 }
6207
Jeff Layton0cd126b2010-02-10 16:18:26 -05006208 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006209 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006210 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006211 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006212 rc = -EIO;
6213 goto QAllEAsOut;
6214 }
6215
Jeff Laytonf0d38682010-02-10 16:18:26 -05006216 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006217 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006218 temp_fea = ea_response_data->list;
6219 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006220 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006221 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006222 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006223
Jeff Layton6e462b92010-02-10 16:18:26 -05006224 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006225 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006226 /* make sure we can read name_len and value_len */
6227 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006228 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006229 rc = -EIO;
6230 goto QAllEAsOut;
6231 }
6232
6233 name_len = temp_fea->name_len;
6234 value_len = le16_to_cpu(temp_fea->value_len);
6235 list_len -= name_len + 1 + value_len;
6236 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006237 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006238 rc = -EIO;
6239 goto QAllEAsOut;
6240 }
6241
Jeff Layton31c05192010-02-10 16:18:26 -05006242 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006243 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006244 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006245 temp_ptr += name_len + 1;
6246 rc = value_len;
6247 if (buf_size == 0)
6248 goto QAllEAsOut;
6249 if ((size_t)value_len > buf_size) {
6250 rc = -ERANGE;
6251 goto QAllEAsOut;
6252 }
6253 memcpy(EAData, temp_ptr, value_len);
6254 goto QAllEAsOut;
6255 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006256 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006257 /* account for prefix user. and trailing null */
6258 rc += (5 + 1 + name_len);
6259 if (rc < (int) buf_size) {
6260 memcpy(EAData, "user.", 5);
6261 EAData += 5;
6262 memcpy(EAData, temp_ptr, name_len);
6263 EAData += name_len;
6264 /* null terminate name */
6265 *EAData = 0;
6266 ++EAData;
6267 } else if (buf_size == 0) {
6268 /* skip copy - calc size only */
6269 } else {
6270 /* stop before overrun buffer */
6271 rc = -ERANGE;
6272 break;
6273 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006274 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006275 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006276 temp_fea = (struct fea *)temp_ptr;
6277 }
6278
Jeff Layton31c05192010-02-10 16:18:26 -05006279 /* didn't find the named attribute */
6280 if (ea_name)
6281 rc = -ENODATA;
6282
Jeff Laytonf0d38682010-02-10 16:18:26 -05006283QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006284 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 if (rc == -EAGAIN)
6286 goto QAllEAsRetry;
6287
6288 return (ssize_t)rc;
6289}
6290
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006292CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6293 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006294 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006295 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296{
6297 struct smb_com_transaction2_spi_req *pSMB = NULL;
6298 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6299 struct fealist *parm_data;
6300 int name_len;
6301 int rc = 0;
6302 int bytes_returned = 0;
6303 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006304 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
Joe Perchesf96637b2013-05-04 22:12:25 -05006306 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307SetEARetry:
6308 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6309 (void **) &pSMBr);
6310 if (rc)
6311 return rc;
6312
6313 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6314 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006315 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6316 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317 name_len++; /* trailing null */
6318 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006319 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 name_len = strnlen(fileName, PATH_MAX);
6321 name_len++; /* trailing null */
6322 strncpy(pSMB->FileName, fileName, name_len);
6323 }
6324
6325 params = 6 + name_len;
6326
6327 /* done calculating parms using name_len of file name,
6328 now use name_len to calculate length of ea name
6329 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006330 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 name_len = 0;
6332 else
Steve French50c2f752007-07-13 00:33:32 +00006333 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006335 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006337 /* BB find max SMB PDU from sess */
6338 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339 pSMB->MaxSetupCount = 0;
6340 pSMB->Reserved = 0;
6341 pSMB->Flags = 0;
6342 pSMB->Timeout = 0;
6343 pSMB->Reserved2 = 0;
6344 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006345 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 offset = param_offset + params;
6347 pSMB->InformationLevel =
6348 cpu_to_le16(SMB_SET_FILE_EA);
6349
Arnd Bergmannade7db92018-02-02 16:48:47 +01006350 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6352 pSMB->DataOffset = cpu_to_le16(offset);
6353 pSMB->SetupCount = 1;
6354 pSMB->Reserved3 = 0;
6355 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6356 byte_count = 3 /* pad */ + params + count;
6357 pSMB->DataCount = cpu_to_le16(count);
6358 parm_data->list_len = cpu_to_le32(count);
6359 parm_data->list[0].EA_flags = 0;
6360 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006361 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006363 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006364 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365 parm_data->list[0].name[name_len] = 0;
6366 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6367 /* caller ensures that ea_value_len is less than 64K but
6368 we need to ensure that it fits within the smb */
6369
Steve French50c2f752007-07-13 00:33:32 +00006370 /*BB add length check to see if it would fit in
6371 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006372 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6373 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006374 memcpy(parm_data->list[0].name+name_len+1,
6375 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376
6377 pSMB->TotalDataCount = pSMB->DataCount;
6378 pSMB->ParameterCount = cpu_to_le16(params);
6379 pSMB->TotalParameterCount = pSMB->ParameterCount;
6380 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006381 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 pSMB->ByteCount = cpu_to_le16(byte_count);
6383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006385 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006386 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387
6388 cifs_buf_release(pSMB);
6389
6390 if (rc == -EAGAIN)
6391 goto SetEARetry;
6392
6393 return rc;
6394}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395#endif
Steve French0eff0e22011-02-24 05:39:23 +00006396
6397#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6398/*
6399 * Years ago the kernel added a "dnotify" function for Samba server,
6400 * to allow network clients (such as Windows) to display updated
6401 * lists of files in directory listings automatically when
6402 * files are added by one user when another user has the
6403 * same directory open on their desktop. The Linux cifs kernel
6404 * client hooked into the kernel side of this interface for
6405 * the same reason, but ironically when the VFS moved from
6406 * "dnotify" to "inotify" it became harder to plug in Linux
6407 * network file system clients (the most obvious use case
6408 * for notify interfaces is when multiple users can update
6409 * the contents of the same directory - exactly what network
6410 * file systems can do) although the server (Samba) could
6411 * still use it. For the short term we leave the worker
6412 * function ifdeffed out (below) until inotify is fixed
6413 * in the VFS to make it easier to plug in network file
6414 * system clients. If inotify turns out to be permanently
6415 * incompatible for network fs clients, we could instead simply
6416 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6417 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006418int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006419 const int notify_subdirs, const __u16 netfid,
6420 __u32 filter, struct file *pfile, int multishot,
6421 const struct nls_table *nls_codepage)
6422{
6423 int rc = 0;
6424 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6425 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6426 struct dir_notify_req *dnotify_req;
6427 int bytes_returned;
6428
Joe Perchesf96637b2013-05-04 22:12:25 -05006429 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006430 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6431 (void **) &pSMBr);
6432 if (rc)
6433 return rc;
6434
6435 pSMB->TotalParameterCount = 0 ;
6436 pSMB->TotalDataCount = 0;
6437 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006438 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006439 pSMB->MaxSetupCount = 4;
6440 pSMB->Reserved = 0;
6441 pSMB->ParameterOffset = 0;
6442 pSMB->DataCount = 0;
6443 pSMB->DataOffset = 0;
6444 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6445 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6446 pSMB->ParameterCount = pSMB->TotalParameterCount;
6447 if (notify_subdirs)
6448 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6449 pSMB->Reserved2 = 0;
6450 pSMB->CompletionFilter = cpu_to_le32(filter);
6451 pSMB->Fid = netfid; /* file handle always le */
6452 pSMB->ByteCount = 0;
6453
6454 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6455 (struct smb_hdr *)pSMBr, &bytes_returned,
6456 CIFS_ASYNC_OP);
6457 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006458 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006459 } else {
6460 /* Add file to outstanding requests */
6461 /* BB change to kmem cache alloc */
6462 dnotify_req = kmalloc(
6463 sizeof(struct dir_notify_req),
6464 GFP_KERNEL);
6465 if (dnotify_req) {
6466 dnotify_req->Pid = pSMB->hdr.Pid;
6467 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6468 dnotify_req->Mid = pSMB->hdr.Mid;
6469 dnotify_req->Tid = pSMB->hdr.Tid;
6470 dnotify_req->Uid = pSMB->hdr.Uid;
6471 dnotify_req->netfid = netfid;
6472 dnotify_req->pfile = pfile;
6473 dnotify_req->filter = filter;
6474 dnotify_req->multishot = multishot;
6475 spin_lock(&GlobalMid_Lock);
6476 list_add_tail(&dnotify_req->lhead,
6477 &GlobalDnotifyReqList);
6478 spin_unlock(&GlobalMid_Lock);
6479 } else
6480 rc = -ENOMEM;
6481 }
6482 cifs_buf_release(pSMB);
6483 return rc;
6484}
6485#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */