blob: 1529a088383d048554cfd129de7b8898aa12f6e1 [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 Frencha45443472005-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 Frencha45443472005-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 Layton50285882013-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
Long Libb4c0412018-04-17 12:17:08 -0700458 if (cifs_rdma_enabled(server) && server->sign)
459 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled");
460
Jeff Layton9ddec562013-05-26 07:00:58 -0400461 return 0;
462}
463
Jeff Layton2190eca2013-05-26 07:00:57 -0400464#ifdef CONFIG_CIFS_WEAK_PW_HASH
465static int
Jeff Layton3f618222013-06-12 19:52:14 -0500466decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400467{
468 __s16 tmp;
469 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
470
471 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
472 return -EOPNOTSUPP;
473
Jeff Layton2190eca2013-05-26 07:00:57 -0400474 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
475 server->maxReq = min_t(unsigned int,
476 le16_to_cpu(rsp->MaxMpxCount),
477 cifs_max_pending);
478 set_credits(server, server->maxReq);
479 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400480 /* even though we do not use raw we might as well set this
481 accurately, in case we ever find a need for it */
482 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
483 server->max_rw = 0xFF00;
484 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
485 } else {
486 server->max_rw = 0;/* do not need to use raw anyway */
487 server->capabilities = CAP_MPX_MODE;
488 }
489 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
490 if (tmp == -1) {
491 /* OS/2 often does not set timezone therefore
492 * we must use server time to calc time zone.
493 * Could deviate slightly from the right zone.
494 * Smallest defined timezone difference is 15 minutes
495 * (i.e. Nepal). Rounding up/down is done to match
496 * this requirement.
497 */
498 int val, seconds, remain, result;
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700499 struct timespec ts;
500 unsigned long utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400501 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
502 rsp->SrvTime.Time, 0);
503 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700504 (int)ts.tv_sec, (int)utc,
505 (int)(utc - ts.tv_sec));
506 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400507 seconds = abs(val);
508 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
509 remain = seconds % MIN_TZ_ADJ;
510 if (remain >= (MIN_TZ_ADJ / 2))
511 result += MIN_TZ_ADJ;
512 if (val < 0)
513 result = -result;
514 server->timeAdj = result;
515 } else {
516 server->timeAdj = (int)tmp;
517 server->timeAdj *= 60; /* also in seconds */
518 }
519 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
520
521
522 /* BB get server time for time conversions and add
523 code to use it and timezone since this is not UTC */
524
525 if (rsp->EncryptionKeyLength ==
526 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
527 memcpy(server->cryptkey, rsp->EncryptionKey,
528 CIFS_CRYPTO_KEY_SIZE);
529 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
530 return -EIO; /* need cryptkey unless plain text */
531 }
532
533 cifs_dbg(FYI, "LANMAN negotiated\n");
534 return 0;
535}
536#else
537static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500538decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400539{
540 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
541 return -EOPNOTSUPP;
542}
543#endif
544
Jeff Layton91934002013-05-26 07:00:58 -0400545static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500546should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400547{
Jeff Layton3f618222013-06-12 19:52:14 -0500548 switch (sectype) {
549 case RawNTLMSSP:
550 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400551 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500552 case Unspecified:
553 if (global_secflags &
554 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
555 return true;
556 /* Fallthrough */
557 default:
558 return false;
559 }
Jeff Layton91934002013-05-26 07:00:58 -0400560}
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400563CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 NEGOTIATE_REQ *pSMB;
566 NEGOTIATE_RSP *pSMBr;
567 int rc = 0;
568 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000569 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400570 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 u16 count;
572
Jeff Layton3534b852013-05-24 07:41:01 -0400573 if (!server) {
574 WARN(1, "%s: server is NULL!\n", __func__);
575 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
Jeff Layton3534b852013-05-24 07:41:01 -0400577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
579 (void **) &pSMB, (void **) &pSMBr);
580 if (rc)
581 return rc;
Steve French750d1152006-06-27 06:28:30 +0000582
Pavel Shilovsky88257362012-05-23 14:01:59 +0400583 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000584 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000585
Jeff Layton3f618222013-06-12 19:52:14 -0500586 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400587 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000588 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
589 }
Steve French50c2f752007-07-13 00:33:32 +0000590
Steve French39798772006-05-31 22:40:51 +0000591 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000592 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000593 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
594 count += strlen(protocols[i].name) + 1;
595 /* null at end of source and target buffers anyway */
596 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000597 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 pSMB->ByteCount = cpu_to_le16(count);
599
600 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000602 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000603 goto neg_err_exit;
604
Jeff Layton9bf67e52010-04-24 07:57:46 -0400605 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500606 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000607 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400608 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000609 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000610 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000611 could not negotiate a common dialect */
612 rc = -EOPNOTSUPP;
613 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000614 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400615 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500616 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400617 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000618 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000619 /* unknown wct */
620 rc = -EOPNOTSUPP;
621 goto neg_err_exit;
622 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400623 /* else wct == 17, NTLM or better */
624
Steve French96daf2b2011-05-27 04:34:02 +0000625 server->sec_mode = pSMBr->SecurityMode;
626 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500627 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000628
Steve French254e55e2006-06-04 05:53:15 +0000629 /* one byte, so no need to convert this or EncryptionKeyLen from
630 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300631 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
632 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400633 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000634 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400635 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000636 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500637 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000638 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000639 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
640 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400641
Jeff Laytone598d1d82013-05-26 07:00:59 -0400642 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
643 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500644 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000645 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100646 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
647 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400648 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500649 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400650 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000651 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400652 } else {
653 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000654 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400655 }
Steve French254e55e2006-06-04 05:53:15 +0000656
657signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400658 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400659 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000660neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700661 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000662
Joe Perchesf96637b2013-05-04 22:12:25 -0500663 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 return rc;
665}
666
667int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400668CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
670 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Joe Perchesf96637b2013-05-04 22:12:25 -0500673 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500674
675 /* BB: do we need to check this? These should never be NULL. */
676 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
677 return -EIO;
678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500680 * No need to return error on this operation if tid invalidated and
681 * closed on server already e.g. due to tcp session crashing. Also,
682 * the tcon is no longer on the list, so no need to take lock before
683 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 */
Steve French268875b2009-06-25 00:29:21 +0000685 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000686 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Steve French50c2f752007-07-13 00:33:32 +0000688 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700689 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500690 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return rc;
Steve French133672e2007-11-13 22:41:37 +0000692
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400693 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700694 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500696 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Steve French50c2f752007-07-13 00:33:32 +0000698 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500699 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc == -EAGAIN)
701 rc = 0;
702
703 return rc;
704}
705
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706/*
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
710 *
711 * FIXME: maybe we should consider checking that the reply matches request?
712 */
713static void
714cifs_echo_callback(struct mid_q_entry *mid)
715{
716 struct TCP_Server_Info *server = mid->callback_data;
717
718 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400719 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500720}
721
722int
723CIFSSMBEcho(struct TCP_Server_Info *server)
724{
725 ECHO_REQ *smb;
726 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800727 struct kvec iov[2];
728 struct smb_rqst rqst = { .rq_iov = iov,
729 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500730
Joe Perchesf96637b2013-05-04 22:12:25 -0500731 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500732
733 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
734 if (rc)
735 return rc;
736
Steve French26c9cb62017-05-02 13:35:20 -0500737 if (server->capabilities & CAP_UNICODE)
738 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
739
Jeff Layton766fdbb2011-01-11 07:24:21 -0500740 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000741 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500742 smb->hdr.WordCount = 1;
743 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400744 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500745 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000746 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800747
748 iov[0].iov_len = 4;
749 iov[0].iov_base = smb;
750 iov[1].iov_len = get_rfc1002_length(smb);
751 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500752
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800753 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400754 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500755 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500756 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500757
758 cifs_small_buf_release(smb);
759
760 return rc;
761}
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400764CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 LOGOFF_ANDX_REQ *pSMB;
767 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Joe Perchesf96637b2013-05-04 22:12:25 -0500769 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500770
771 /*
772 * BB: do we need to check validity of ses and server? They should
773 * always be valid since we have an active reference. If not, that
774 * should probably be a BUG()
775 */
776 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return -EIO;
778
Steve Frenchd7b619c2010-02-25 05:36:46 +0000779 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000780 if (ses->need_reconnect)
781 goto session_already_dead; /* no need to send SMBlogoff if uid
782 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
784 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000785 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return rc;
787 }
788
Pavel Shilovsky88257362012-05-23 14:01:59 +0400789 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700790
Jeff Layton38d77c52013-05-26 07:01:00 -0400791 if (ses->server->sign)
792 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 pSMB->hdr.Uid = ses->Suid;
795
796 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400797 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700798 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000799session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000800 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000803 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 error */
805 if (rc == -EAGAIN)
806 rc = 0;
807 return rc;
808}
809
810int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400811CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
812 const char *fileName, __u16 type,
813 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000814{
815 TRANSACTION2_SPI_REQ *pSMB = NULL;
816 TRANSACTION2_SPI_RSP *pSMBr = NULL;
817 struct unlink_psx_rq *pRqD;
818 int name_len;
819 int rc = 0;
820 int bytes_returned = 0;
821 __u16 params, param_offset, offset, byte_count;
822
Joe Perchesf96637b2013-05-04 22:12:25 -0500823 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000824PsxDelete:
825 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
826 (void **) &pSMBr);
827 if (rc)
828 return rc;
829
830 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
831 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600832 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
833 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000834 name_len++; /* trailing null */
835 name_len *= 2;
836 } else { /* BB add path length overrun check */
837 name_len = strnlen(fileName, PATH_MAX);
838 name_len++; /* trailing null */
839 strncpy(pSMB->FileName, fileName, name_len);
840 }
841
842 params = 6 + name_len;
843 pSMB->MaxParameterCount = cpu_to_le16(2);
844 pSMB->MaxDataCount = 0; /* BB double check this with jra */
845 pSMB->MaxSetupCount = 0;
846 pSMB->Reserved = 0;
847 pSMB->Flags = 0;
848 pSMB->Timeout = 0;
849 pSMB->Reserved2 = 0;
850 param_offset = offsetof(struct smb_com_transaction2_spi_req,
851 InformationLevel) - 4;
852 offset = param_offset + params;
853
854 /* Setup pointer to Request Data (inode type) */
855 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
856 pRqD->type = cpu_to_le16(type);
857 pSMB->ParameterOffset = cpu_to_le16(param_offset);
858 pSMB->DataOffset = cpu_to_le16(offset);
859 pSMB->SetupCount = 1;
860 pSMB->Reserved3 = 0;
861 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
862 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
863
864 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
865 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
866 pSMB->ParameterCount = cpu_to_le16(params);
867 pSMB->TotalParameterCount = pSMB->ParameterCount;
868 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
869 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000870 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000871 pSMB->ByteCount = cpu_to_le16(byte_count);
872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000874 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500875 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000876 cifs_buf_release(pSMB);
877
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400878 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000879
880 if (rc == -EAGAIN)
881 goto PsxDelete;
882
883 return rc;
884}
885
886int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700887CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
888 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
890 DELETE_FILE_REQ *pSMB = NULL;
891 DELETE_FILE_RSP *pSMBr = NULL;
892 int rc = 0;
893 int bytes_returned;
894 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500895 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897DelFileRetry:
898 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
899 (void **) &pSMBr);
900 if (rc)
901 return rc;
902
903 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
905 PATH_MAX, cifs_sb->local_nls,
906 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 name_len++; /* trailing null */
908 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700909 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700910 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700912 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 }
914 pSMB->SearchAttributes =
915 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
916 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000917 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 pSMB->ByteCount = cpu_to_le16(name_len + 1);
919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400921 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000922 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500923 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 cifs_buf_release(pSMB);
926 if (rc == -EAGAIN)
927 goto DelFileRetry;
928
929 return rc;
930}
931
932int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400933CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
934 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
936 DELETE_DIRECTORY_REQ *pSMB = NULL;
937 DELETE_DIRECTORY_RSP *pSMBr = NULL;
938 int rc = 0;
939 int bytes_returned;
940 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500941 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Joe Perchesf96637b2013-05-04 22:12:25 -0500943 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944RmDirRetry:
945 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
946 (void **) &pSMBr);
947 if (rc)
948 return rc;
949
950 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
952 PATH_MAX, cifs_sb->local_nls,
953 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 name_len++; /* trailing null */
955 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700956 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400957 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400959 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 }
961
962 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000963 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 pSMB->ByteCount = cpu_to_le16(name_len + 1);
965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400967 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000968 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500969 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
971 cifs_buf_release(pSMB);
972 if (rc == -EAGAIN)
973 goto RmDirRetry;
974 return rc;
975}
976
977int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300978CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
979 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980{
981 int rc = 0;
982 CREATE_DIRECTORY_REQ *pSMB = NULL;
983 CREATE_DIRECTORY_RSP *pSMBr = NULL;
984 int bytes_returned;
985 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500986 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Joe Perchesf96637b2013-05-04 22:12:25 -0500988 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989MkDirRetry:
990 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
991 (void **) &pSMBr);
992 if (rc)
993 return rc;
994
995 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600996 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300997 PATH_MAX, cifs_sb->local_nls,
998 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 name_len++; /* trailing null */
1000 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001001 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 name_len = strnlen(name, PATH_MAX);
1003 name_len++; /* trailing null */
1004 strncpy(pSMB->DirName, name, name_len);
1005 }
1006
1007 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001008 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1010 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1011 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001012 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001013 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001014 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 cifs_buf_release(pSMB);
1017 if (rc == -EAGAIN)
1018 goto MkDirRetry;
1019 return rc;
1020}
1021
Steve French2dd29d32007-04-23 22:07:35 +00001022int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001023CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1024 __u32 posix_flags, __u64 mode, __u16 *netfid,
1025 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1026 const char *name, const struct nls_table *nls_codepage,
1027 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001028{
1029 TRANSACTION2_SPI_REQ *pSMB = NULL;
1030 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1031 int name_len;
1032 int rc = 0;
1033 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001034 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001035 OPEN_PSX_REQ *pdata;
1036 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001037
Joe Perchesf96637b2013-05-04 22:12:25 -05001038 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001039PsxCreat:
1040 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1041 (void **) &pSMBr);
1042 if (rc)
1043 return rc;
1044
1045 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1046 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001047 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1048 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001049 name_len++; /* trailing null */
1050 name_len *= 2;
1051 } else { /* BB improve the check for buffer overruns BB */
1052 name_len = strnlen(name, PATH_MAX);
1053 name_len++; /* trailing null */
1054 strncpy(pSMB->FileName, name, name_len);
1055 }
1056
1057 params = 6 + name_len;
1058 count = sizeof(OPEN_PSX_REQ);
1059 pSMB->MaxParameterCount = cpu_to_le16(2);
1060 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1061 pSMB->MaxSetupCount = 0;
1062 pSMB->Reserved = 0;
1063 pSMB->Flags = 0;
1064 pSMB->Timeout = 0;
1065 pSMB->Reserved2 = 0;
1066 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001067 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001068 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001069 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001070 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001071 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001072 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001073 pdata->OpenFlags = cpu_to_le32(*pOplock);
1074 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1075 pSMB->DataOffset = cpu_to_le16(offset);
1076 pSMB->SetupCount = 1;
1077 pSMB->Reserved3 = 0;
1078 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1079 byte_count = 3 /* pad */ + params + count;
1080
1081 pSMB->DataCount = cpu_to_le16(count);
1082 pSMB->ParameterCount = cpu_to_le16(params);
1083 pSMB->TotalDataCount = pSMB->DataCount;
1084 pSMB->TotalParameterCount = pSMB->ParameterCount;
1085 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1086 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001087 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001088 pSMB->ByteCount = cpu_to_le16(byte_count);
1089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1091 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001092 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001093 goto psx_create_err;
1094 }
1095
Joe Perchesf96637b2013-05-04 22:12:25 -05001096 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001097 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1098
Jeff Layton820a8032011-05-04 08:05:26 -04001099 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001100 rc = -EIO; /* bad smb */
1101 goto psx_create_err;
1102 }
1103
1104 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001105 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001106 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001107
Steve French2dd29d32007-04-23 22:07:35 +00001108 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001109 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001110 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1111 /* Let caller know file was created so we can set the mode. */
1112 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001113 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001114 *pOplock |= CIFS_CREATE_ACTION;
1115 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001116 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1117 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001118 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001119 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001120 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001121 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001122 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001123 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001124 goto psx_create_err;
1125 }
Steve French50c2f752007-07-13 00:33:32 +00001126 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001127 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001128 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001129 }
Steve French2dd29d32007-04-23 22:07:35 +00001130
1131psx_create_err:
1132 cifs_buf_release(pSMB);
1133
Steve French65bc98b2009-07-10 15:27:25 +00001134 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001135 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001136 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001137 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001138
1139 if (rc == -EAGAIN)
1140 goto PsxCreat;
1141
Steve French50c2f752007-07-13 00:33:32 +00001142 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001143}
1144
Steve Frencha9d02ad2005-08-24 23:06:05 -07001145static __u16 convert_disposition(int disposition)
1146{
1147 __u16 ofun = 0;
1148
1149 switch (disposition) {
1150 case FILE_SUPERSEDE:
1151 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1152 break;
1153 case FILE_OPEN:
1154 ofun = SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_CREATE:
1157 ofun = SMBOPEN_OCREATE;
1158 break;
1159 case FILE_OPEN_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1161 break;
1162 case FILE_OVERWRITE:
1163 ofun = SMBOPEN_OTRUNC;
1164 break;
1165 case FILE_OVERWRITE_IF:
1166 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1167 break;
1168 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001169 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170 ofun = SMBOPEN_OAPPEND; /* regular open */
1171 }
1172 return ofun;
1173}
1174
Jeff Layton35fc37d2008-05-14 10:22:03 -07001175static int
1176access_flags_to_smbopen_mode(const int access_flags)
1177{
1178 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1179
1180 if (masked_flags == GENERIC_READ)
1181 return SMBOPEN_READ;
1182 else if (masked_flags == GENERIC_WRITE)
1183 return SMBOPEN_WRITE;
1184
1185 /* just go for read/write */
1186 return SMBOPEN_READWRITE;
1187}
1188
Steve Frencha9d02ad2005-08-24 23:06:05 -07001189int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001190SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001191 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001192 const int access_flags, const int create_options, __u16 *netfid,
1193 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001194 const struct nls_table *nls_codepage, int remap)
1195{
1196 int rc = -EACCES;
1197 OPENX_REQ *pSMB = NULL;
1198 OPENX_RSP *pSMBr = NULL;
1199 int bytes_returned;
1200 int name_len;
1201 __u16 count;
1202
1203OldOpenRetry:
1204 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1205 (void **) &pSMBr);
1206 if (rc)
1207 return rc;
1208
1209 pSMB->AndXCommand = 0xFF; /* none */
1210
1211 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1212 count = 1; /* account for one byte pad to word boundary */
1213 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001214 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1215 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 name_len++; /* trailing null */
1217 name_len *= 2;
1218 } else { /* BB improve check for buffer overruns BB */
1219 count = 0; /* no pad */
1220 name_len = strnlen(fileName, PATH_MAX);
1221 name_len++; /* trailing null */
1222 strncpy(pSMB->fileName, fileName, name_len);
1223 }
1224 if (*pOplock & REQ_OPLOCK)
1225 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001226 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001228
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001230 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1232 /* set file as system file if special file such
1233 as fifo and server expecting SFU style and
1234 no Unix extensions */
1235
Steve French790fe572007-07-07 19:25:05 +00001236 if (create_options & CREATE_OPTION_SPECIAL)
1237 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001238 else /* BB FIXME BB */
1239 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240
Jeff Layton67750fb2008-05-09 22:28:02 +00001241 if (create_options & CREATE_OPTION_READONLY)
1242 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243
1244 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001245/* pSMB->CreateOptions = cpu_to_le32(create_options &
1246 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001248
1249 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001250 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001252 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253
1254 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001256 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001257 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001259 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 } else {
1261 /* BB verify if wct == 15 */
1262
Steve French582d21e2008-05-13 04:54:12 +00001263/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264
1265 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1266 /* Let caller know file was created so we can set the mode. */
1267 /* Do we care about the CreateAction in any other cases? */
1268 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001269/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 *pOplock |= CIFS_CREATE_ACTION; */
1271 /* BB FIXME END */
1272
Steve French790fe572007-07-07 19:25:05 +00001273 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1275 pfile_info->LastAccessTime = 0; /* BB fixme */
1276 pfile_info->LastWriteTime = 0; /* BB fixme */
1277 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001278 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001279 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001280 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001281 pfile_info->AllocationSize =
1282 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1283 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001284 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001285 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001286 }
1287 }
1288
1289 cifs_buf_release(pSMB);
1290 if (rc == -EAGAIN)
1291 goto OldOpenRetry;
1292 return rc;
1293}
1294
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001296CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1297 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298{
1299 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001300 OPEN_REQ *req = NULL;
1301 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 int bytes_returned;
1303 int name_len;
1304 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001305 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1306 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001307 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001308 const struct nls_table *nls = cifs_sb->local_nls;
1309 int create_options = oparms->create_options;
1310 int desired_access = oparms->desired_access;
1311 int disposition = oparms->disposition;
1312 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
1314openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001315 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1316 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (rc)
1318 return rc;
1319
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001320 /* no commands go after this */
1321 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001323 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1324 /* account for one byte pad to word boundary */
1325 count = 1;
1326 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1327 path, PATH_MAX, nls, remap);
1328 /* trailing null */
1329 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001331 req->NameLength = cpu_to_le16(name_len);
1332 } else {
1333 /* BB improve check for buffer overruns BB */
1334 /* no pad */
1335 count = 0;
1336 name_len = strnlen(path, PATH_MAX);
1337 /* trailing null */
1338 name_len++;
1339 req->NameLength = cpu_to_le16(name_len);
1340 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001342
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001343 if (*oplock & REQ_OPLOCK)
1344 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1345 else if (*oplock & REQ_BATCHOPLOCK)
1346 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1347
1348 req->DesiredAccess = cpu_to_le32(desired_access);
1349 req->AllocationSize = 0;
1350
1351 /*
1352 * Set file as system file if special file such as fifo and server
1353 * expecting SFU style and no Unix extensions.
1354 */
1355 if (create_options & CREATE_OPTION_SPECIAL)
1356 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1357 else
1358 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1359
1360 /*
1361 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1362 * sensitive checks for other servers such as Samba.
1363 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001365 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Jeff Layton67750fb2008-05-09 22:28:02 +00001367 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001368 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001369
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001370 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1371 req->CreateDisposition = cpu_to_le32(disposition);
1372 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1373
Steve French09d1db52005-04-28 22:41:08 -07001374 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001375 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1376 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001379 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001381 req->ByteCount = cpu_to_le16(count);
1382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1383 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001384 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001386 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001387 cifs_buf_release(req);
1388 if (rc == -EAGAIN)
1389 goto openRetry;
1390 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001392
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001393 /* 1 byte no need to le_to_cpu */
1394 *oplock = rsp->OplockLevel;
1395 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001396 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001397
1398 /* Let caller know file was created so we can set the mode. */
1399 /* Do we care about the CreateAction in any other cases? */
1400 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1401 *oplock |= CIFS_CREATE_ACTION;
1402
1403 if (buf) {
1404 /* copy from CreationTime to Attributes */
1405 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1406 /* the file_info buf is endian converted by caller */
1407 buf->AllocationSize = rsp->AllocationSize;
1408 buf->EndOfFile = rsp->EndOfFile;
1409 buf->NumberOfLinks = cpu_to_le32(1);
1410 buf->DeletePending = 0;
1411 }
1412
1413 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 return rc;
1415}
1416
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001417/*
1418 * Discard any remaining data in the current SMB. To do this, we borrow the
1419 * current bigbuf.
1420 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001421int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001422cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001423{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001424 unsigned int rfclen = server->pdu_size;
1425 int remaining = rfclen + server->vals->header_preamble_size -
1426 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427
1428 while (remaining > 0) {
1429 int length;
1430
1431 length = cifs_read_from_socket(server, server->bigbuf,
1432 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001433 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001434 if (length < 0)
1435 return length;
1436 server->total_read += length;
1437 remaining -= length;
1438 }
1439
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440 return 0;
1441}
1442
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001443static int
1444cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1445{
1446 int length;
1447 struct cifs_readdata *rdata = mid->callback_data;
1448
Pavel Shilovsky350be252017-04-10 10:31:33 -07001449 length = cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001450 dequeue_mid(mid, rdata->result);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001451 mid->resp_buf = server->smallbuf;
1452 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001453 return length;
1454}
1455
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001456int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1458{
1459 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001460 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001461 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001462 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001463 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001464 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001465 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001466
Joe Perchesf96637b2013-05-04 22:12:25 -05001467 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1468 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001469
1470 /*
1471 * read the rest of READ_RSP header (sans Data array), or whatever we
1472 * can if there's not enough data. At this point, we've read down to
1473 * the Mid.
1474 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001475 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001476 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001477
Al Viroa6137302016-01-09 19:37:16 -05001478 length = cifs_read_from_socket(server,
1479 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001480 if (length < 0)
1481 return length;
1482 server->total_read += length;
1483
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001484 if (server->ops->is_session_expired &&
1485 server->ops->is_session_expired(buf)) {
1486 cifs_reconnect(server);
1487 wake_up(&server->response_q);
1488 return -1;
1489 }
1490
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001491 if (server->ops->is_status_pending &&
1492 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001493 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001494 return -1;
1495 }
1496
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001497 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001498 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001499 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001500 cifs_dbg(FYI, "%s: server returned error %d\n",
1501 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001502 return cifs_readv_discard(server, mid);
1503 }
1504
1505 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001506 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001507 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1508 __func__, server->total_read,
1509 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001510 rdata->result = -EIO;
1511 return cifs_readv_discard(server, mid);
1512 }
1513
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001514 data_offset = server->ops->read_data_offset(buf) +
1515 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516 if (data_offset < server->total_read) {
1517 /*
1518 * win2k8 sometimes sends an offset of 0 when the read
1519 * is beyond the EOF. Treat it as if the data starts just after
1520 * the header.
1521 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001522 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1523 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524 data_offset = server->total_read;
1525 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1526 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001527 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1528 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529 rdata->result = -EIO;
1530 return cifs_readv_discard(server, mid);
1531 }
1532
Joe Perchesf96637b2013-05-04 22:12:25 -05001533 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1534 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001535
1536 len = data_offset - server->total_read;
1537 if (len > 0) {
1538 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001539 length = cifs_read_from_socket(server,
1540 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541 if (length < 0)
1542 return length;
1543 server->total_read += length;
1544 }
1545
1546 /* set up first iov for signature check */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001547 rdata->iov[0].iov_base = buf;
1548 rdata->iov[0].iov_len = 4;
1549 rdata->iov[1].iov_base = buf + 4;
1550 rdata->iov[1].iov_len = server->total_read - 4;
1551 cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
1552 rdata->iov[0].iov_base, server->total_read);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001553
1554 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001555#ifdef CONFIG_CIFS_SMB_DIRECT
1556 use_rdma_mr = rdata->mr;
1557#endif
1558 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1559 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560 /* data_len is corrupt -- discard frame */
1561 rdata->result = -EIO;
1562 return cifs_readv_discard(server, mid);
1563 }
1564
Jeff Layton8321fec2012-09-19 06:22:32 -07001565 length = rdata->read_into_pages(server, rdata, data_len);
1566 if (length < 0)
1567 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001568
Jeff Layton8321fec2012-09-19 06:22:32 -07001569 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001570
Joe Perchesf96637b2013-05-04 22:12:25 -05001571 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1572 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573
1574 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001575 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001576 return cifs_readv_discard(server, mid);
1577
1578 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001579 mid->resp_buf = server->smallbuf;
1580 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001581 return length;
1582}
1583
1584static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585cifs_readv_callback(struct mid_q_entry *mid)
1586{
1587 struct cifs_readdata *rdata = mid->callback_data;
1588 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1589 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001590 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1591 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001592 .rq_pages = rdata->pages,
1593 .rq_npages = rdata->nr_pages,
1594 .rq_pagesz = rdata->pagesz,
1595 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001596
Joe Perchesf96637b2013-05-04 22:12:25 -05001597 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1598 __func__, mid->mid, mid->mid_state, rdata->result,
1599 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001600
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001601 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602 case MID_RESPONSE_RECEIVED:
1603 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001604 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001605 int rc = 0;
1606
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001607 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001608 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001609 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001610 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1611 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001612 }
1613 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001614 task_io_account_read(rdata->got_bytes);
1615 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001616 break;
1617 case MID_REQUEST_SUBMITTED:
1618 case MID_RETRY_NEEDED:
1619 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001620 if (server->sign && rdata->got_bytes)
1621 /* reset bytes number since we can not check a sign */
1622 rdata->got_bytes = 0;
1623 /* FIXME: should this be counted toward the initiating task? */
1624 task_io_account_read(rdata->got_bytes);
1625 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001626 break;
1627 default:
1628 rdata->result = -EIO;
1629 }
1630
Jeff Laytonda472fc2012-03-23 14:40:53 -04001631 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001632 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001633 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001634}
1635
1636/* cifs_async_readv - send an async write, and set up mid to handle result */
1637int
1638cifs_async_readv(struct cifs_readdata *rdata)
1639{
1640 int rc;
1641 READ_REQ *smb = NULL;
1642 int wct;
1643 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001644 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1645 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001646
Joe Perchesf96637b2013-05-04 22:12:25 -05001647 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1648 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001649
1650 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1651 wct = 12;
1652 else {
1653 wct = 10; /* old style read */
1654 if ((rdata->offset >> 32) > 0) {
1655 /* can not handle this big offset for old */
1656 return -EIO;
1657 }
1658 }
1659
1660 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1661 if (rc)
1662 return rc;
1663
1664 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1665 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1666
1667 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001668 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001669 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1670 if (wct == 12)
1671 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1672 smb->Remaining = 0;
1673 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1674 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1675 if (wct == 12)
1676 smb->ByteCount = 0;
1677 else {
1678 /* old style read */
1679 struct smb_com_readx_req *smbr =
1680 (struct smb_com_readx_req *)smb;
1681 smbr->ByteCount = 0;
1682 }
1683
1684 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001685 rdata->iov[0].iov_base = smb;
1686 rdata->iov[0].iov_len = 4;
1687 rdata->iov[1].iov_base = (char *)smb + 4;
1688 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001689
Jeff Layton6993f742012-05-16 07:13:17 -04001690 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001691 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001692 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001693
1694 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001695 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001696 else
1697 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001698
1699 cifs_small_buf_release(smb);
1700 return rc;
1701}
1702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001704CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1705 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706{
1707 int rc = -EACCES;
1708 READ_REQ *pSMB = NULL;
1709 READ_RSP *pSMBr = NULL;
1710 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001711 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001712 int resp_buf_type = 0;
1713 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001714 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001715 __u32 pid = io_parms->pid;
1716 __u16 netfid = io_parms->netfid;
1717 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001718 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001719 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
Joe Perchesf96637b2013-05-04 22:12:25 -05001721 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001722 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001723 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001724 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001725 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001726 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001727 /* can not handle this big offset for old */
1728 return -EIO;
1729 }
1730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731
1732 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001733 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 if (rc)
1735 return rc;
1736
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001737 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1738 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1739
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 /* tcon and ses pointer are checked in smb_init */
1741 if (tcon->ses->server == NULL)
1742 return -ECONNABORTED;
1743
Steve Frenchec637e32005-12-12 20:53:18 -08001744 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001746 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001747 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001748 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 pSMB->Remaining = 0;
1751 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1752 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001753 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001754 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1755 else {
1756 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001757 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001758 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001759 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001760 }
Steve Frenchec637e32005-12-12 20:53:18 -08001761
1762 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001763 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001764 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1765 CIFS_LOG_ERROR, &rsp_iov);
1766 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001767 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001768 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001770 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 } else {
1772 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1773 data_length = data_length << 16;
1774 data_length += le16_to_cpu(pSMBr->DataLength);
1775 *nbytes = data_length;
1776
1777 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001778 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001780 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001781 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 rc = -EIO;
1783 *nbytes = 0;
1784 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001785 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001786 le16_to_cpu(pSMBr->DataOffset);
1787/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001788 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001789 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001790 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001791 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001792 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 }
1794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
Steve French790fe572007-07-07 19:25:05 +00001796 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001797 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001798 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001799 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001800 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001801 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001802 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001803 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001804 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001805 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001806
1807 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 since file handle passed in no longer valid */
1809 return rc;
1810}
1811
Steve Frenchec637e32005-12-12 20:53:18 -08001812
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001814CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001815 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816{
1817 int rc = -EACCES;
1818 WRITE_REQ *pSMB = NULL;
1819 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001820 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 __u32 bytes_sent;
1822 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001823 __u32 pid = io_parms->pid;
1824 __u16 netfid = io_parms->netfid;
1825 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001826 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001827 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
Steve Frencha24e2d72010-04-03 17:20:21 +00001829 *nbytes = 0;
1830
Joe Perchesf96637b2013-05-04 22:12:25 -05001831 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001832 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001833 return -ECONNABORTED;
1834
Steve French790fe572007-07-07 19:25:05 +00001835 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001836 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001837 else {
Steve French1c955182005-08-30 20:58:07 -07001838 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001839 if ((offset >> 32) > 0) {
1840 /* can not handle big offset for old srv */
1841 return -EIO;
1842 }
1843 }
Steve French1c955182005-08-30 20:58:07 -07001844
1845 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 (void **) &pSMBr);
1847 if (rc)
1848 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001849
1850 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1851 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 /* tcon and ses pointer are checked in smb_init */
1854 if (tcon->ses->server == NULL)
1855 return -ECONNABORTED;
1856
1857 pSMB->AndXCommand = 0xFF; /* none */
1858 pSMB->Fid = netfid;
1859 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001860 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001861 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 pSMB->Reserved = 0xFFFFFFFF;
1864 pSMB->WriteMode = 0;
1865 pSMB->Remaining = 0;
1866
Steve French50c2f752007-07-13 00:33:32 +00001867 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 can send more if LARGE_WRITE_X capability returned by the server and if
1869 our buffer is big enough or if we convert to iovecs on socket writes
1870 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001871 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1873 } else {
1874 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1875 & ~0xFF;
1876 }
1877
1878 if (bytes_sent > count)
1879 bytes_sent = count;
1880 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001881 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001882 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001883 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001884 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 /* No buffer */
1886 cifs_buf_release(pSMB);
1887 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001888 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001889 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001890 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001891 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001892 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001893
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1895 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001896 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001897
Steve French790fe572007-07-07 19:25:05 +00001898 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001899 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001900 else { /* old style write has byte count 4 bytes earlier
1901 so 4 bytes pad */
1902 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001903 (struct smb_com_writex_req *)pSMB;
1904 pSMBW->ByteCount = cpu_to_le16(byte_count);
1905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001908 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001909 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001911 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 } else {
1913 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1914 *nbytes = (*nbytes) << 16;
1915 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301916
1917 /*
1918 * Mask off high 16 bits when bytes written as returned by the
1919 * server is greater than bytes requested by the client. Some
1920 * OS/2 servers are known to set incorrect CountHigh values.
1921 */
1922 if (*nbytes > count)
1923 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 }
1925
1926 cifs_buf_release(pSMB);
1927
Steve French50c2f752007-07-13 00:33:32 +00001928 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 since file handle passed in no longer valid */
1930
1931 return rc;
1932}
1933
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001934void
1935cifs_writedata_release(struct kref *refcount)
1936{
1937 struct cifs_writedata *wdata = container_of(refcount,
1938 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001939#ifdef CONFIG_CIFS_SMB_DIRECT
1940 if (wdata->mr) {
1941 smbd_deregister_mr(wdata->mr);
1942 wdata->mr = NULL;
1943 }
1944#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001945
1946 if (wdata->cfile)
1947 cifsFileInfo_put(wdata->cfile);
1948
1949 kfree(wdata);
1950}
1951
1952/*
1953 * Write failed with a retryable error. Resend the write request. It's also
1954 * possible that the page was redirtied so re-clean the page.
1955 */
1956static void
1957cifs_writev_requeue(struct cifs_writedata *wdata)
1958{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001959 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001960 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001961 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001962 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001963
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001964 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1965 i = 0;
1966 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001967 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001968 struct cifs_writedata *wdata2;
1969 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001970
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001971 wsize = server->ops->wp_retry_size(inode);
1972 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001973 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001974 if (!nr_pages) {
1975 rc = -ENOTSUPP;
1976 break;
1977 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001978 cur_len = nr_pages * PAGE_SIZE;
1979 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001980 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001981 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001982 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001983 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001984 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001985
1986 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1987 if (!wdata2) {
1988 rc = -ENOMEM;
1989 break;
1990 }
1991
1992 for (j = 0; j < nr_pages; j++) {
1993 wdata2->pages[j] = wdata->pages[i + j];
1994 lock_page(wdata2->pages[j]);
1995 clear_page_dirty_for_io(wdata2->pages[j]);
1996 }
1997
1998 wdata2->sync_mode = wdata->sync_mode;
1999 wdata2->nr_pages = nr_pages;
2000 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002001 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002002 wdata2->tailsz = tailsz;
2003 wdata2->bytes = cur_len;
2004
2005 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2006 if (!wdata2->cfile) {
2007 cifs_dbg(VFS, "No writable handles for inode\n");
2008 rc = -EBADF;
2009 break;
2010 }
2011 wdata2->pid = wdata2->cfile->pid;
2012 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2013
2014 for (j = 0; j < nr_pages; j++) {
2015 unlock_page(wdata2->pages[j]);
2016 if (rc != 0 && rc != -EAGAIN) {
2017 SetPageError(wdata2->pages[j]);
2018 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002019 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002020 }
2021 }
2022
2023 if (rc) {
2024 kref_put(&wdata2->refcount, cifs_writedata_release);
2025 if (rc == -EAGAIN)
2026 continue;
2027 break;
2028 }
2029
2030 rest_len -= cur_len;
2031 i += nr_pages;
2032 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002033
2034 mapping_set_error(inode->i_mapping, rc);
2035 kref_put(&wdata->refcount, cifs_writedata_release);
2036}
2037
Jeff Laytonc2e87642012-03-23 14:40:55 -04002038void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002039cifs_writev_complete(struct work_struct *work)
2040{
2041 struct cifs_writedata *wdata = container_of(work,
2042 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002043 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002044 int i = 0;
2045
2046 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002047 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002048 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002049 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002050 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2051 wdata->bytes);
2052 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2053 return cifs_writev_requeue(wdata);
2054
2055 for (i = 0; i < wdata->nr_pages; i++) {
2056 struct page *page = wdata->pages[i];
2057 if (wdata->result == -EAGAIN)
2058 __set_page_dirty_nobuffers(page);
2059 else if (wdata->result < 0)
2060 SetPageError(page);
2061 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002062 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002063 }
2064 if (wdata->result != -EAGAIN)
2065 mapping_set_error(inode->i_mapping, wdata->result);
2066 kref_put(&wdata->refcount, cifs_writedata_release);
2067}
2068
2069struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002070cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002071{
2072 struct cifs_writedata *wdata;
2073
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002074 /* writedata + number of page pointers */
2075 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002076 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002078 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002079 INIT_LIST_HEAD(&wdata->list);
2080 init_completion(&wdata->done);
2081 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082 }
2083 return wdata;
2084}
2085
2086/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002087 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002088 * workqueue completion task.
2089 */
2090static void
2091cifs_writev_callback(struct mid_q_entry *mid)
2092{
2093 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002094 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095 unsigned int written;
2096 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2097
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002098 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099 case MID_RESPONSE_RECEIVED:
2100 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2101 if (wdata->result != 0)
2102 break;
2103
2104 written = le16_to_cpu(smb->CountHigh);
2105 written <<= 16;
2106 written += le16_to_cpu(smb->Count);
2107 /*
2108 * Mask off high 16 bits when bytes written as returned
2109 * by the server is greater than bytes requested by the
2110 * client. OS/2 servers are known to set incorrect
2111 * CountHigh values.
2112 */
2113 if (written > wdata->bytes)
2114 written &= 0xFFFF;
2115
2116 if (written < wdata->bytes)
2117 wdata->result = -ENOSPC;
2118 else
2119 wdata->bytes = written;
2120 break;
2121 case MID_REQUEST_SUBMITTED:
2122 case MID_RETRY_NEEDED:
2123 wdata->result = -EAGAIN;
2124 break;
2125 default:
2126 wdata->result = -EIO;
2127 break;
2128 }
2129
Jeff Laytonda472fc2012-03-23 14:40:53 -04002130 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002131 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002132 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002133}
2134
2135/* cifs_async_writev - send an async write, and set up mid to handle result */
2136int
Steve French4a5c80d2014-02-07 20:45:12 -06002137cifs_async_writev(struct cifs_writedata *wdata,
2138 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002139{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002140 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002141 WRITE_REQ *smb = NULL;
2142 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002143 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002144 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002145 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002146
2147 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2148 wct = 14;
2149 } else {
2150 wct = 12;
2151 if (wdata->offset >> 32 > 0) {
2152 /* can not handle big offset for old srv */
2153 return -EIO;
2154 }
2155 }
2156
2157 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2158 if (rc)
2159 goto async_writev_out;
2160
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002161 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2162 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002163
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002164 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002165 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002166 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2167 if (wct == 14)
2168 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2169 smb->Reserved = 0xFFFFFFFF;
2170 smb->WriteMode = 0;
2171 smb->Remaining = 0;
2172
2173 smb->DataOffset =
2174 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2175
2176 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002177 iov[0].iov_len = 4;
2178 iov[0].iov_base = smb;
2179 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2180 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002181
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002182 rqst.rq_iov = iov;
2183 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002184 rqst.rq_pages = wdata->pages;
2185 rqst.rq_npages = wdata->nr_pages;
2186 rqst.rq_pagesz = wdata->pagesz;
2187 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002188
Joe Perchesf96637b2013-05-04 22:12:25 -05002189 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2190 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002191
2192 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2193 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2194
2195 if (wct == 14) {
2196 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2197 put_bcc(wdata->bytes + 1, &smb->hdr);
2198 } else {
2199 /* wct == 12 */
2200 struct smb_com_writex_req *smbw =
2201 (struct smb_com_writex_req *)smb;
2202 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2203 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002204 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002205 }
2206
2207 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002208 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002209 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002210
2211 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002212 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002213 else
Steve French4a5c80d2014-02-07 20:45:12 -06002214 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002215
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002216async_writev_out:
2217 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002218 return rc;
2219}
2220
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002221int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002222CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002223 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224{
2225 int rc = -EACCES;
2226 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002227 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002228 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002229 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002230 __u32 pid = io_parms->pid;
2231 __u16 netfid = io_parms->netfid;
2232 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002233 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002234 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002235 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002237 *nbytes = 0;
2238
Joe Perchesf96637b2013-05-04 22:12:25 -05002239 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002240
Steve French4c3130e2008-12-09 00:28:16 +00002241 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002242 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002243 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002244 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002245 if ((offset >> 32) > 0) {
2246 /* can not handle big offset for old srv */
2247 return -EIO;
2248 }
2249 }
Steve French8cc64c62005-10-03 13:49:43 -07002250 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 if (rc)
2252 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002253
2254 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2255 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 /* tcon and ses pointer are checked in smb_init */
2258 if (tcon->ses->server == NULL)
2259 return -ECONNABORTED;
2260
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002261 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 pSMB->Fid = netfid;
2263 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002264 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002265 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 pSMB->Reserved = 0xFFFFFFFF;
2267 pSMB->WriteMode = 0;
2268 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002271 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
Steve French3e844692005-10-03 13:37:24 -07002273 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2274 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002275 /* header + 1 byte pad */
2276 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002277 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002278 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002279 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002280 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002281 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002282 pSMB->ByteCount = cpu_to_le16(count + 1);
2283 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002284 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002285 (struct smb_com_writex_req *)pSMB;
2286 pSMBW->ByteCount = cpu_to_le16(count + 5);
2287 }
Steve French3e844692005-10-03 13:37:24 -07002288 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002289 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002290 iov[0].iov_len = smb_hdr_len + 4;
2291 else /* wct == 12 pad bigger by four bytes */
2292 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002293
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002294 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2295 &rsp_iov);
2296 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002297 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002299 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002300 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002301 /* presumably this can not happen, but best to be safe */
2302 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002303 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002304 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002305 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2306 *nbytes = (*nbytes) << 16;
2307 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302308
2309 /*
2310 * Mask off high 16 bits when bytes written as returned by the
2311 * server is greater than bytes requested by the client. OS/2
2312 * servers are known to set incorrect CountHigh values.
2313 */
2314 if (*nbytes > count)
2315 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002318 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Steve French50c2f752007-07-13 00:33:32 +00002320 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 since file handle passed in no longer valid */
2322
2323 return rc;
2324}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002325
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002326int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2327 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002328 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2329{
2330 int rc = 0;
2331 LOCK_REQ *pSMB = NULL;
2332 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002333 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002334 int resp_buf_type;
2335 __u16 count;
2336
Joe Perchesf96637b2013-05-04 22:12:25 -05002337 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2338 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002339
2340 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2341 if (rc)
2342 return rc;
2343
2344 pSMB->Timeout = 0;
2345 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2346 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2347 pSMB->LockType = lock_type;
2348 pSMB->AndXCommand = 0xFF; /* none */
2349 pSMB->Fid = netfid; /* netfid stays le */
2350
2351 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2352 inc_rfc1001_len(pSMB, count);
2353 pSMB->ByteCount = cpu_to_le16(count);
2354
2355 iov[0].iov_base = (char *)pSMB;
2356 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2357 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2358 iov[1].iov_base = (char *)buf;
2359 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2360
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002361 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002362 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2363 &rsp_iov);
2364 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002365 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002366 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002367
2368 return rc;
2369}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002370
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002372CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002373 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002375 const __u32 numLock, const __u8 lockType,
2376 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377{
2378 int rc = 0;
2379 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002380/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002382 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 __u16 count;
2384
Joe Perchesf96637b2013-05-04 22:12:25 -05002385 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2386 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002387 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2388
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 if (rc)
2390 return rc;
2391
Steve French790fe572007-07-07 19:25:05 +00002392 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002393 /* no response expected */
2394 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002396 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002397 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2399 } else {
2400 pSMB->Timeout = 0;
2401 }
2402
2403 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2404 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2405 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002406 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 pSMB->AndXCommand = 0xFF; /* none */
2408 pSMB->Fid = smb_file_id; /* netfid stays le */
2409
Steve French790fe572007-07-07 19:25:05 +00002410 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002411 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 /* BB where to store pid high? */
2413 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2414 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2415 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2416 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2417 count = sizeof(LOCKING_ANDX_RANGE);
2418 } else {
2419 /* oplock break */
2420 count = 0;
2421 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002422 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 pSMB->ByteCount = cpu_to_le16(count);
2424
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002425 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002426 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002427 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002428 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002429 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002430 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002431 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002432 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002433 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Steve French50c2f752007-07-13 00:33:32 +00002435 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 since file handle passed in no longer valid */
2437 return rc;
2438}
2439
2440int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002441CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002442 const __u16 smb_file_id, const __u32 netpid,
2443 const loff_t start_offset, const __u64 len,
2444 struct file_lock *pLockData, const __u16 lock_type,
2445 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002446{
2447 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2448 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002449 struct cifs_posix_lock *parm_data;
2450 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002451 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002452 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002453 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002454 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002455 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002456 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002457
Joe Perchesf96637b2013-05-04 22:12:25 -05002458 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002459
Steve French08547b02006-02-28 22:39:25 +00002460 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2461
2462 if (rc)
2463 return rc;
2464
2465 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2466
Steve French50c2f752007-07-13 00:33:32 +00002467 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002468 pSMB->MaxSetupCount = 0;
2469 pSMB->Reserved = 0;
2470 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002471 pSMB->Reserved2 = 0;
2472 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2473 offset = param_offset + params;
2474
Steve French08547b02006-02-28 22:39:25 +00002475 count = sizeof(struct cifs_posix_lock);
2476 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002477 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002478 pSMB->SetupCount = 1;
2479 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002480 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002481 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2482 else
2483 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2484 byte_count = 3 /* pad */ + params + count;
2485 pSMB->DataCount = cpu_to_le16(count);
2486 pSMB->ParameterCount = cpu_to_le16(params);
2487 pSMB->TotalDataCount = pSMB->DataCount;
2488 pSMB->TotalParameterCount = pSMB->ParameterCount;
2489 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002490 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002491 (((char *) &pSMB->hdr.Protocol) + offset);
2492
2493 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002494 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002495 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002496 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002497 pSMB->Timeout = cpu_to_le32(-1);
2498 } else
2499 pSMB->Timeout = 0;
2500
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002501 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002502 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002503 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002504
2505 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002506 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002507 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2508 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002509 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002510 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002511 if (waitFlag) {
2512 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2513 (struct smb_hdr *) pSMBr, &bytes_returned);
2514 } else {
Steve French133672e2007-11-13 22:41:37 +00002515 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002516 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002517 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002518 &resp_buf_type, timeout, &rsp_iov);
2519 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002520 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002521 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002522
Steve French08547b02006-02-28 22:39:25 +00002523 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002524 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002525 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002526 /* lock structure can be returned on get */
2527 __u16 data_offset;
2528 __u16 data_count;
2529 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002530
Jeff Layton820a8032011-05-04 08:05:26 -04002531 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002532 rc = -EIO; /* bad smb */
2533 goto plk_err_exit;
2534 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002535 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2536 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002537 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002538 rc = -EIO;
2539 goto plk_err_exit;
2540 }
2541 parm_data = (struct cifs_posix_lock *)
2542 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002543 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002544 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002545 else {
2546 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002547 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002548 pLockData->fl_type = F_RDLCK;
2549 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002550 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002551 pLockData->fl_type = F_WRLCK;
2552
Steve French5443d132011-03-13 05:08:25 +00002553 pLockData->fl_start = le64_to_cpu(parm_data->start);
2554 pLockData->fl_end = pLockData->fl_start +
2555 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002556 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002557 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002558 }
Steve French50c2f752007-07-13 00:33:32 +00002559
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002560plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002561 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002562
Steve French08547b02006-02-28 22:39:25 +00002563 /* Note: On -EAGAIN error only caller can retry on handle based calls
2564 since file handle passed in no longer valid */
2565
2566 return rc;
2567}
2568
2569
2570int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002571CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572{
2573 int rc = 0;
2574 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002575 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
2577/* do not retry on dead session on close */
2578 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002579 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 return 0;
2581 if (rc)
2582 return rc;
2583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002585 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002587 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002588 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002589 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002591 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002593 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 }
2595 }
2596
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002598 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 rc = 0;
2600
2601 return rc;
2602}
2603
2604int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002605CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002606{
2607 int rc = 0;
2608 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002609 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002610
2611 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2612 if (rc)
2613 return rc;
2614
2615 pSMB->FileID = (__u16) smb_file_id;
2616 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002617 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002618 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002619 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002620 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002621 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002622
2623 return rc;
2624}
2625
2626int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002627CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002628 const char *from_name, const char *to_name,
2629 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630{
2631 int rc = 0;
2632 RENAME_REQ *pSMB = NULL;
2633 RENAME_RSP *pSMBr = NULL;
2634 int bytes_returned;
2635 int name_len, name_len2;
2636 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002637 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638
Joe Perchesf96637b2013-05-04 22:12:25 -05002639 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640renameRetry:
2641 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2642 (void **) &pSMBr);
2643 if (rc)
2644 return rc;
2645
2646 pSMB->BufferFormat = 0x04;
2647 pSMB->SearchAttributes =
2648 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2649 ATTR_DIRECTORY);
2650
2651 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002652 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2653 from_name, PATH_MAX,
2654 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 name_len++; /* trailing null */
2656 name_len *= 2;
2657 pSMB->OldFileName[name_len] = 0x04; /* pad */
2658 /* protocol requires ASCII signature byte on Unicode string */
2659 pSMB->OldFileName[name_len + 1] = 0x00;
2660 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002661 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002662 to_name, PATH_MAX, cifs_sb->local_nls,
2663 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2665 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002666 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002667 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002669 strncpy(pSMB->OldFileName, from_name, name_len);
2670 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 name_len2++; /* trailing null */
2672 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002673 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 name_len2++; /* trailing null */
2675 name_len2++; /* signature byte */
2676 }
2677
2678 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002679 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 pSMB->ByteCount = cpu_to_le16(count);
2681
2682 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2683 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002684 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002685 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002686 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 cifs_buf_release(pSMB);
2689
2690 if (rc == -EAGAIN)
2691 goto renameRetry;
2692
2693 return rc;
2694}
2695
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002696int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002697 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002698 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699{
2700 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2701 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002702 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 char *data_offset;
2704 char dummy_string[30];
2705 int rc = 0;
2706 int bytes_returned = 0;
2707 int len_of_str;
2708 __u16 params, param_offset, offset, count, byte_count;
2709
Joe Perchesf96637b2013-05-04 22:12:25 -05002710 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2712 (void **) &pSMBr);
2713 if (rc)
2714 return rc;
2715
2716 params = 6;
2717 pSMB->MaxSetupCount = 0;
2718 pSMB->Reserved = 0;
2719 pSMB->Flags = 0;
2720 pSMB->Timeout = 0;
2721 pSMB->Reserved2 = 0;
2722 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2723 offset = param_offset + params;
2724
2725 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2726 rename_info = (struct set_file_rename *) data_offset;
2727 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002728 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 pSMB->SetupCount = 1;
2730 pSMB->Reserved3 = 0;
2731 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2732 byte_count = 3 /* pad */ + params;
2733 pSMB->ParameterCount = cpu_to_le16(params);
2734 pSMB->TotalParameterCount = pSMB->ParameterCount;
2735 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2736 pSMB->DataOffset = cpu_to_le16(offset);
2737 /* construct random name ".cifs_tmp<inodenum><mid>" */
2738 rename_info->overwrite = cpu_to_le32(1);
2739 rename_info->root_fid = 0;
2740 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002741 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002742 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002743 len_of_str =
2744 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002745 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002747 len_of_str =
2748 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002749 target_name, PATH_MAX, nls_codepage,
2750 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 }
2752 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002753 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 byte_count += count;
2755 pSMB->DataCount = cpu_to_le16(count);
2756 pSMB->TotalDataCount = pSMB->DataCount;
2757 pSMB->Fid = netfid;
2758 pSMB->InformationLevel =
2759 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2760 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002761 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 pSMB->ByteCount = cpu_to_le16(byte_count);
2763 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002765 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002766 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002767 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2768 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002769
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 cifs_buf_release(pSMB);
2771
2772 /* Note: On -EAGAIN error only caller can retry on handle based calls
2773 since file handle passed in no longer valid */
2774
2775 return rc;
2776}
2777
2778int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002779CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2780 const char *fromName, const __u16 target_tid, const char *toName,
2781 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782{
2783 int rc = 0;
2784 COPY_REQ *pSMB = NULL;
2785 COPY_RSP *pSMBr = NULL;
2786 int bytes_returned;
2787 int name_len, name_len2;
2788 __u16 count;
2789
Joe Perchesf96637b2013-05-04 22:12:25 -05002790 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791copyRetry:
2792 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2793 (void **) &pSMBr);
2794 if (rc)
2795 return rc;
2796
2797 pSMB->BufferFormat = 0x04;
2798 pSMB->Tid2 = target_tid;
2799
2800 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2801
2802 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002803 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2804 fromName, PATH_MAX, nls_codepage,
2805 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 name_len++; /* trailing null */
2807 name_len *= 2;
2808 pSMB->OldFileName[name_len] = 0x04; /* pad */
2809 /* protocol requires ASCII signature byte on Unicode string */
2810 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002811 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002812 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2813 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2815 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002816 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len = strnlen(fromName, PATH_MAX);
2818 name_len++; /* trailing null */
2819 strncpy(pSMB->OldFileName, fromName, name_len);
2820 name_len2 = strnlen(toName, PATH_MAX);
2821 name_len2++; /* trailing null */
2822 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2823 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2824 name_len2++; /* trailing null */
2825 name_len2++; /* signature byte */
2826 }
2827
2828 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002829 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 pSMB->ByteCount = cpu_to_le16(count);
2831
2832 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2833 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2834 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002835 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2836 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 }
Steve French0d817bc2008-05-22 02:02:03 +00002838 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839
2840 if (rc == -EAGAIN)
2841 goto copyRetry;
2842
2843 return rc;
2844}
2845
2846int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002847CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002849 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850{
2851 TRANSACTION2_SPI_REQ *pSMB = NULL;
2852 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2853 char *data_offset;
2854 int name_len;
2855 int name_len_target;
2856 int rc = 0;
2857 int bytes_returned = 0;
2858 __u16 params, param_offset, offset, byte_count;
2859
Joe Perchesf96637b2013-05-04 22:12:25 -05002860 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861createSymLinkRetry:
2862 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2863 (void **) &pSMBr);
2864 if (rc)
2865 return rc;
2866
2867 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2868 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002869 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2870 /* find define for this maxpathcomponent */
2871 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 name_len++; /* trailing null */
2873 name_len *= 2;
2874
Steve French50c2f752007-07-13 00:33:32 +00002875 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 name_len = strnlen(fromName, PATH_MAX);
2877 name_len++; /* trailing null */
2878 strncpy(pSMB->FileName, fromName, name_len);
2879 }
2880 params = 6 + name_len;
2881 pSMB->MaxSetupCount = 0;
2882 pSMB->Reserved = 0;
2883 pSMB->Flags = 0;
2884 pSMB->Timeout = 0;
2885 pSMB->Reserved2 = 0;
2886 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002887 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 offset = param_offset + params;
2889
2890 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2891 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2892 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002893 cifsConvertToUTF16((__le16 *) data_offset, toName,
2894 /* find define for this maxpathcomponent */
2895 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 name_len_target++; /* trailing null */
2897 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002898 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 name_len_target = strnlen(toName, PATH_MAX);
2900 name_len_target++; /* trailing null */
2901 strncpy(data_offset, toName, name_len_target);
2902 }
2903
2904 pSMB->MaxParameterCount = cpu_to_le16(2);
2905 /* BB find exact max on data count below from sess */
2906 pSMB->MaxDataCount = cpu_to_le16(1000);
2907 pSMB->SetupCount = 1;
2908 pSMB->Reserved3 = 0;
2909 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2910 byte_count = 3 /* pad */ + params + name_len_target;
2911 pSMB->DataCount = cpu_to_le16(name_len_target);
2912 pSMB->ParameterCount = cpu_to_le16(params);
2913 pSMB->TotalDataCount = pSMB->DataCount;
2914 pSMB->TotalParameterCount = pSMB->ParameterCount;
2915 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2916 pSMB->DataOffset = cpu_to_le16(offset);
2917 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2918 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002919 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 pSMB->ByteCount = cpu_to_le16(byte_count);
2921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002923 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002924 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002925 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2926 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
Steve French0d817bc2008-05-22 02:02:03 +00002928 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
2930 if (rc == -EAGAIN)
2931 goto createSymLinkRetry;
2932
2933 return rc;
2934}
2935
2936int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002937CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002939 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940{
2941 TRANSACTION2_SPI_REQ *pSMB = NULL;
2942 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2943 char *data_offset;
2944 int name_len;
2945 int name_len_target;
2946 int rc = 0;
2947 int bytes_returned = 0;
2948 __u16 params, param_offset, offset, byte_count;
2949
Joe Perchesf96637b2013-05-04 22:12:25 -05002950 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951createHardLinkRetry:
2952 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2953 (void **) &pSMBr);
2954 if (rc)
2955 return rc;
2956
2957 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002958 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2959 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len++; /* trailing null */
2961 name_len *= 2;
2962
Steve French50c2f752007-07-13 00:33:32 +00002963 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len = strnlen(toName, PATH_MAX);
2965 name_len++; /* trailing null */
2966 strncpy(pSMB->FileName, toName, name_len);
2967 }
2968 params = 6 + name_len;
2969 pSMB->MaxSetupCount = 0;
2970 pSMB->Reserved = 0;
2971 pSMB->Flags = 0;
2972 pSMB->Timeout = 0;
2973 pSMB->Reserved2 = 0;
2974 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002975 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 offset = param_offset + params;
2977
2978 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2980 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002981 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 name_len_target++; /* trailing null */
2984 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002985 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 name_len_target = strnlen(fromName, PATH_MAX);
2987 name_len_target++; /* trailing null */
2988 strncpy(data_offset, fromName, name_len_target);
2989 }
2990
2991 pSMB->MaxParameterCount = cpu_to_le16(2);
2992 /* BB find exact max on data count below from sess*/
2993 pSMB->MaxDataCount = cpu_to_le16(1000);
2994 pSMB->SetupCount = 1;
2995 pSMB->Reserved3 = 0;
2996 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2997 byte_count = 3 /* pad */ + params + name_len_target;
2998 pSMB->ParameterCount = cpu_to_le16(params);
2999 pSMB->TotalParameterCount = pSMB->ParameterCount;
3000 pSMB->DataCount = cpu_to_le16(name_len_target);
3001 pSMB->TotalDataCount = pSMB->DataCount;
3002 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3003 pSMB->DataOffset = cpu_to_le16(offset);
3004 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3005 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003006 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 pSMB->ByteCount = cpu_to_le16(byte_count);
3008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003010 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003011 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003012 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3013 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
3015 cifs_buf_release(pSMB);
3016 if (rc == -EAGAIN)
3017 goto createHardLinkRetry;
3018
3019 return rc;
3020}
3021
3022int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003023CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003024 const char *from_name, const char *to_name,
3025 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026{
3027 int rc = 0;
3028 NT_RENAME_REQ *pSMB = NULL;
3029 RENAME_RSP *pSMBr = NULL;
3030 int bytes_returned;
3031 int name_len, name_len2;
3032 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003033 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034
Joe Perchesf96637b2013-05-04 22:12:25 -05003035 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036winCreateHardLinkRetry:
3037
3038 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3039 (void **) &pSMBr);
3040 if (rc)
3041 return rc;
3042
3043 pSMB->SearchAttributes =
3044 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3045 ATTR_DIRECTORY);
3046 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3047 pSMB->ClusterCount = 0;
3048
3049 pSMB->BufferFormat = 0x04;
3050
3051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3052 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003053 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3054 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 name_len++; /* trailing null */
3056 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003057
3058 /* protocol specifies ASCII buffer format (0x04) for unicode */
3059 pSMB->OldFileName[name_len] = 0x04;
3060 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003062 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003063 to_name, PATH_MAX, cifs_sb->local_nls,
3064 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3066 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003067 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003068 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003070 strncpy(pSMB->OldFileName, from_name, name_len);
3071 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 name_len2++; /* trailing null */
3073 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003074 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 name_len2++; /* trailing null */
3076 name_len2++; /* signature byte */
3077 }
3078
3079 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003080 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 pSMB->ByteCount = cpu_to_le16(count);
3082
3083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003085 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003086 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003087 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003088
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 cifs_buf_release(pSMB);
3090 if (rc == -EAGAIN)
3091 goto winCreateHardLinkRetry;
3092
3093 return rc;
3094}
3095
3096int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003097CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003098 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003099 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100{
3101/* SMB_QUERY_FILE_UNIX_LINK */
3102 TRANSACTION2_QPI_REQ *pSMB = NULL;
3103 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3104 int rc = 0;
3105 int bytes_returned;
3106 int name_len;
3107 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003108 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
Joe Perchesf96637b2013-05-04 22:12:25 -05003110 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
3112querySymLinkRetry:
3113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3114 (void **) &pSMBr);
3115 if (rc)
3116 return rc;
3117
3118 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3119 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003120 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3121 searchName, PATH_MAX, nls_codepage,
3122 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 name_len++; /* trailing null */
3124 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003125 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 name_len = strnlen(searchName, PATH_MAX);
3127 name_len++; /* trailing null */
3128 strncpy(pSMB->FileName, searchName, name_len);
3129 }
3130
3131 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3132 pSMB->TotalDataCount = 0;
3133 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003134 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 pSMB->MaxSetupCount = 0;
3136 pSMB->Reserved = 0;
3137 pSMB->Flags = 0;
3138 pSMB->Timeout = 0;
3139 pSMB->Reserved2 = 0;
3140 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003141 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 pSMB->DataCount = 0;
3143 pSMB->DataOffset = 0;
3144 pSMB->SetupCount = 1;
3145 pSMB->Reserved3 = 0;
3146 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3147 byte_count = params + 1 /* pad */ ;
3148 pSMB->TotalParameterCount = cpu_to_le16(params);
3149 pSMB->ParameterCount = pSMB->TotalParameterCount;
3150 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3151 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003152 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 pSMB->ByteCount = cpu_to_le16(byte_count);
3154
3155 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3156 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3157 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003158 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 } else {
3160 /* decode response */
3161
3162 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003164 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003165 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003167 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003168 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
Jeff Layton460b9692009-04-30 07:17:56 -04003170 data_start = ((char *) &pSMBr->hdr.Protocol) +
3171 le16_to_cpu(pSMBr->t2.DataOffset);
3172
Steve French0e0d2cf2009-05-01 05:27:32 +00003173 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3174 is_unicode = true;
3175 else
3176 is_unicode = false;
3177
Steve French737b7582005-04-28 22:41:06 -07003178 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003179 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3180 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003181 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003182 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 }
3184 }
3185 cifs_buf_release(pSMB);
3186 if (rc == -EAGAIN)
3187 goto querySymLinkRetry;
3188 return rc;
3189}
3190
Steve Frenchc52a9552011-02-24 06:16:22 +00003191/*
3192 * Recent Windows versions now create symlinks more frequently
3193 * and they use the "reparse point" mechanism below. We can of course
3194 * do symlinks nicely to Samba and other servers which support the
3195 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3196 * "MF" symlinks optionally, but for recent Windows we really need to
3197 * reenable the code below and fix the cifs_symlink callers to handle this.
3198 * In the interim this code has been moved to its own config option so
3199 * it is not compiled in by default until callers fixed up and more tested.
3200 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003202CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3203 __u16 fid, char **symlinkinfo,
3204 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205{
3206 int rc = 0;
3207 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003208 struct smb_com_transaction_ioctl_req *pSMB;
3209 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003210 bool is_unicode;
3211 unsigned int sub_len;
3212 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003213 struct reparse_symlink_data *reparse_buf;
3214 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003215 __u32 data_offset, data_count;
3216 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003218 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3220 (void **) &pSMBr);
3221 if (rc)
3222 return rc;
3223
3224 pSMB->TotalParameterCount = 0 ;
3225 pSMB->TotalDataCount = 0;
3226 pSMB->MaxParameterCount = cpu_to_le32(2);
3227 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003228 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 pSMB->MaxSetupCount = 4;
3230 pSMB->Reserved = 0;
3231 pSMB->ParameterOffset = 0;
3232 pSMB->DataCount = 0;
3233 pSMB->DataOffset = 0;
3234 pSMB->SetupCount = 4;
3235 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3236 pSMB->ParameterCount = pSMB->TotalParameterCount;
3237 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3238 pSMB->IsFsctl = 1; /* FSCTL */
3239 pSMB->IsRootFlag = 0;
3240 pSMB->Fid = fid; /* file handle always le */
3241 pSMB->ByteCount = 0;
3242
3243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3245 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003246 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003247 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 }
Steve French989c7e52009-05-02 05:32:20 +00003249
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003250 data_offset = le32_to_cpu(pSMBr->DataOffset);
3251 data_count = le32_to_cpu(pSMBr->DataCount);
3252 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3253 /* BB also check enough total bytes returned */
3254 rc = -EIO; /* bad smb */
3255 goto qreparse_out;
3256 }
3257 if (!data_count || (data_count > 2048)) {
3258 rc = -EIO;
3259 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3260 goto qreparse_out;
3261 }
3262 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003263 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003264 ((char *)&pSMBr->hdr.Protocol + data_offset);
3265 if ((char *)reparse_buf >= end_of_smb) {
3266 rc = -EIO;
3267 goto qreparse_out;
3268 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003269 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3270 cifs_dbg(FYI, "NFS style reparse tag\n");
3271 posix_buf = (struct reparse_posix_data *)reparse_buf;
3272
3273 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3274 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3275 le64_to_cpu(posix_buf->InodeType));
3276 rc = -EOPNOTSUPP;
3277 goto qreparse_out;
3278 }
3279 is_unicode = true;
3280 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3281 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3282 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3283 rc = -EIO;
3284 goto qreparse_out;
3285 }
3286 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3287 sub_len, is_unicode, nls_codepage);
3288 goto qreparse_out;
3289 } else if (reparse_buf->ReparseTag !=
3290 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3291 rc = -EOPNOTSUPP;
3292 goto qreparse_out;
3293 }
3294
3295 /* Reparse tag is NTFS symlink */
3296 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3297 reparse_buf->PathBuffer;
3298 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3299 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003300 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3301 rc = -EIO;
3302 goto qreparse_out;
3303 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003304 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3305 is_unicode = true;
3306 else
3307 is_unicode = false;
3308
3309 /* BB FIXME investigate remapping reserved chars here */
3310 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3311 nls_codepage);
3312 if (!*symlinkinfo)
3313 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003315 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003317 /*
3318 * Note: On -EAGAIN error only caller can retry on handle based calls
3319 * since file handle passed in no longer valid.
3320 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 return rc;
3322}
3323
Steve Frenchc7f508a2013-10-14 15:27:32 -05003324int
3325CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3326 __u16 fid)
3327{
3328 int rc = 0;
3329 int bytes_returned;
3330 struct smb_com_transaction_compr_ioctl_req *pSMB;
3331 struct smb_com_transaction_ioctl_rsp *pSMBr;
3332
3333 cifs_dbg(FYI, "Set compression for %u\n", fid);
3334 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3335 (void **) &pSMBr);
3336 if (rc)
3337 return rc;
3338
3339 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3340
3341 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003342 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003343 pSMB->MaxParameterCount = 0;
3344 pSMB->MaxDataCount = 0;
3345 pSMB->MaxSetupCount = 4;
3346 pSMB->Reserved = 0;
3347 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003348 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003349 pSMB->DataOffset =
3350 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3351 compression_state) - 4); /* 84 */
3352 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003353 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003354 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003355 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003356 pSMB->IsFsctl = 1; /* FSCTL */
3357 pSMB->IsRootFlag = 0;
3358 pSMB->Fid = fid; /* file handle always le */
3359 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003360 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003361 inc_rfc1001_len(pSMB, 5);
3362
3363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3365 if (rc)
3366 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3367
3368 cifs_buf_release(pSMB);
3369
3370 /*
3371 * Note: On -EAGAIN error only caller can retry on handle based calls
3372 * since file handle passed in no longer valid.
3373 */
3374 return rc;
3375}
3376
3377
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378#ifdef CONFIG_CIFS_POSIX
3379
3380/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003381static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003382 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383{
3384 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003385 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3386 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3387 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003388/*
3389 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3390 ace->e_perm, ace->e_tag, ace->e_id);
3391*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
3393 return;
3394}
3395
3396/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003397static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3398 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399{
3400 int size = 0;
3401 int i;
3402 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003403 struct cifs_posix_ace *pACE;
3404 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003405 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
3407 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3408 return -EOPNOTSUPP;
3409
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003410 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 count = le16_to_cpu(cifs_acl->access_entry_count);
3412 pACE = &cifs_acl->ace_array[0];
3413 size = sizeof(struct cifs_posix_acl);
3414 size += sizeof(struct cifs_posix_ace) * count;
3415 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003416 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003417 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3418 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 return -EINVAL;
3420 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003421 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 count = le16_to_cpu(cifs_acl->access_entry_count);
3423 size = sizeof(struct cifs_posix_acl);
3424 size += sizeof(struct cifs_posix_ace) * count;
3425/* skip past access ACEs to get to default ACEs */
3426 pACE = &cifs_acl->ace_array[count];
3427 count = le16_to_cpu(cifs_acl->default_entry_count);
3428 size += sizeof(struct cifs_posix_ace) * count;
3429 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003430 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 return -EINVAL;
3432 } else {
3433 /* illegal type */
3434 return -EINVAL;
3435 }
3436
3437 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003438 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003439 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003440 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 return -ERANGE;
3442 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003443 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3444
Steve Frenchff7feac2005-11-15 16:45:16 -08003445 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003446 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003447 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003448 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 }
3450 }
3451 return size;
3452}
3453
Steve French50c2f752007-07-13 00:33:32 +00003454static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003455 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456{
3457 __u16 rc = 0; /* 0 = ACL converted ok */
3458
Steve Frenchff7feac2005-11-15 16:45:16 -08003459 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3460 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003462 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 /* Probably no need to le convert -1 on any arch but can not hurt */
3464 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003465 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003466 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003467/*
3468 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3469 ace->e_perm, ace->e_tag, ace->e_id);
3470*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 return rc;
3472}
3473
3474/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003475static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3476 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477{
3478 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003479 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003480 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003481 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 int count;
3483 int i;
3484
Steve French790fe572007-07-07 19:25:05 +00003485 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 return 0;
3487
3488 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003489 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3490 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003491 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003492 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3493 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 return 0;
3495 }
3496 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003497 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003498 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003499 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003500 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003501 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003502 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003503 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003504 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 return 0;
3506 }
Steve French50c2f752007-07-13 00:33:32 +00003507 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003508 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003509 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 /* ACE not converted */
3511 break;
3512 }
3513 }
Steve French790fe572007-07-07 19:25:05 +00003514 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3516 rc += sizeof(struct cifs_posix_acl);
3517 /* BB add check to make sure ACL does not overflow SMB */
3518 }
3519 return rc;
3520}
3521
3522int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003523CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003524 const unsigned char *searchName,
3525 char *acl_inf, const int buflen, const int acl_type,
3526 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527{
3528/* SMB_QUERY_POSIX_ACL */
3529 TRANSACTION2_QPI_REQ *pSMB = NULL;
3530 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3531 int rc = 0;
3532 int bytes_returned;
3533 int name_len;
3534 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003535
Joe Perchesf96637b2013-05-04 22:12:25 -05003536 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
3538queryAclRetry:
3539 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3540 (void **) &pSMBr);
3541 if (rc)
3542 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003543
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3545 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003546 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3547 searchName, PATH_MAX, nls_codepage,
3548 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 name_len++; /* trailing null */
3550 name_len *= 2;
3551 pSMB->FileName[name_len] = 0;
3552 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003553 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 name_len = strnlen(searchName, PATH_MAX);
3555 name_len++; /* trailing null */
3556 strncpy(pSMB->FileName, searchName, name_len);
3557 }
3558
3559 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3560 pSMB->TotalDataCount = 0;
3561 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003562 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 pSMB->MaxDataCount = cpu_to_le16(4000);
3564 pSMB->MaxSetupCount = 0;
3565 pSMB->Reserved = 0;
3566 pSMB->Flags = 0;
3567 pSMB->Timeout = 0;
3568 pSMB->Reserved2 = 0;
3569 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003570 offsetof(struct smb_com_transaction2_qpi_req,
3571 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 pSMB->DataCount = 0;
3573 pSMB->DataOffset = 0;
3574 pSMB->SetupCount = 1;
3575 pSMB->Reserved3 = 0;
3576 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3577 byte_count = params + 1 /* pad */ ;
3578 pSMB->TotalParameterCount = cpu_to_le16(params);
3579 pSMB->ParameterCount = pSMB->TotalParameterCount;
3580 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3581 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003582 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 pSMB->ByteCount = cpu_to_le16(byte_count);
3584
3585 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3586 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003587 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003589 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 } else {
3591 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003592
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003595 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 rc = -EIO; /* bad smb */
3597 else {
3598 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3599 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3600 rc = cifs_copy_posix_acl(acl_inf,
3601 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003602 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 }
3604 }
3605 cifs_buf_release(pSMB);
3606 if (rc == -EAGAIN)
3607 goto queryAclRetry;
3608 return rc;
3609}
3610
3611int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003612CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003613 const unsigned char *fileName,
3614 const char *local_acl, const int buflen,
3615 const int acl_type,
3616 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617{
3618 struct smb_com_transaction2_spi_req *pSMB = NULL;
3619 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3620 char *parm_data;
3621 int name_len;
3622 int rc = 0;
3623 int bytes_returned = 0;
3624 __u16 params, byte_count, data_count, param_offset, offset;
3625
Joe Perchesf96637b2013-05-04 22:12:25 -05003626 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627setAclRetry:
3628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003629 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 if (rc)
3631 return rc;
3632 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3633 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003634 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3635 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 name_len++; /* trailing null */
3637 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003638 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 name_len = strnlen(fileName, PATH_MAX);
3640 name_len++; /* trailing null */
3641 strncpy(pSMB->FileName, fileName, name_len);
3642 }
3643 params = 6 + name_len;
3644 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003645 /* BB find max SMB size from sess */
3646 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 pSMB->MaxSetupCount = 0;
3648 pSMB->Reserved = 0;
3649 pSMB->Flags = 0;
3650 pSMB->Timeout = 0;
3651 pSMB->Reserved2 = 0;
3652 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003653 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 offset = param_offset + params;
3655 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3656 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3657
3658 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003659 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660
Steve French790fe572007-07-07 19:25:05 +00003661 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 rc = -EOPNOTSUPP;
3663 goto setACLerrorExit;
3664 }
3665 pSMB->DataOffset = cpu_to_le16(offset);
3666 pSMB->SetupCount = 1;
3667 pSMB->Reserved3 = 0;
3668 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3669 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3670 byte_count = 3 /* pad */ + params + data_count;
3671 pSMB->DataCount = cpu_to_le16(data_count);
3672 pSMB->TotalDataCount = pSMB->DataCount;
3673 pSMB->ParameterCount = cpu_to_le16(params);
3674 pSMB->TotalParameterCount = pSMB->ParameterCount;
3675 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003676 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 pSMB->ByteCount = cpu_to_le16(byte_count);
3678 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003679 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003680 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003681 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682
3683setACLerrorExit:
3684 cifs_buf_release(pSMB);
3685 if (rc == -EAGAIN)
3686 goto setAclRetry;
3687 return rc;
3688}
3689
Steve Frenchf654bac2005-04-28 22:41:04 -07003690/* BB fix tabs in this function FIXME BB */
3691int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003692CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003693 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003694{
Steve French50c2f752007-07-13 00:33:32 +00003695 int rc = 0;
3696 struct smb_t2_qfi_req *pSMB = NULL;
3697 struct smb_t2_qfi_rsp *pSMBr = NULL;
3698 int bytes_returned;
3699 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003700
Joe Perchesf96637b2013-05-04 22:12:25 -05003701 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003702 if (tcon == NULL)
3703 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003704
3705GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003706 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3707 (void **) &pSMBr);
3708 if (rc)
3709 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003710
Steve Frenchad7a2922008-02-07 23:25:02 +00003711 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003712 pSMB->t2.TotalDataCount = 0;
3713 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3714 /* BB find exact max data count below from sess structure BB */
3715 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3716 pSMB->t2.MaxSetupCount = 0;
3717 pSMB->t2.Reserved = 0;
3718 pSMB->t2.Flags = 0;
3719 pSMB->t2.Timeout = 0;
3720 pSMB->t2.Reserved2 = 0;
3721 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3722 Fid) - 4);
3723 pSMB->t2.DataCount = 0;
3724 pSMB->t2.DataOffset = 0;
3725 pSMB->t2.SetupCount = 1;
3726 pSMB->t2.Reserved3 = 0;
3727 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3728 byte_count = params + 1 /* pad */ ;
3729 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3730 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3731 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3732 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003733 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003734 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003735 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003736
Steve French790fe572007-07-07 19:25:05 +00003737 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3738 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3739 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003740 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003741 } else {
3742 /* decode response */
3743 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003744 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003745 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003746 /* If rc should we check for EOPNOSUPP and
3747 disable the srvino flag? or in caller? */
3748 rc = -EIO; /* bad smb */
3749 else {
3750 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3751 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3752 struct file_chattr_info *pfinfo;
3753 /* BB Do we need a cast or hash here ? */
3754 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003755 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003756 rc = -EIO;
3757 goto GetExtAttrOut;
3758 }
3759 pfinfo = (struct file_chattr_info *)
3760 (data_offset + (char *) &pSMBr->hdr.Protocol);
3761 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003762 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003763 }
3764 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003765GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003766 cifs_buf_release(pSMB);
3767 if (rc == -EAGAIN)
3768 goto GetExtAttrRetry;
3769 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003770}
3771
Steve Frenchf654bac2005-04-28 22:41:04 -07003772#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773
Jeff Layton79df1ba2010-12-06 12:52:08 -05003774#ifdef CONFIG_CIFS_ACL
3775/*
3776 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3777 * all NT TRANSACTS that we init here have total parm and data under about 400
3778 * bytes (to fit in small cifs buffer size), which is the case so far, it
3779 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3780 * returned setup area) and MaxParameterCount (returned parms size) must be set
3781 * by caller
3782 */
3783static int
3784smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003785 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003786 void **ret_buf)
3787{
3788 int rc;
3789 __u32 temp_offset;
3790 struct smb_com_ntransact_req *pSMB;
3791
3792 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3793 (void **)&pSMB);
3794 if (rc)
3795 return rc;
3796 *ret_buf = (void *)pSMB;
3797 pSMB->Reserved = 0;
3798 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3799 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003800 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003801 pSMB->ParameterCount = pSMB->TotalParameterCount;
3802 pSMB->DataCount = pSMB->TotalDataCount;
3803 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3804 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3805 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3806 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3807 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3808 pSMB->SubCommand = cpu_to_le16(sub_command);
3809 return 0;
3810}
3811
3812static int
3813validate_ntransact(char *buf, char **ppparm, char **ppdata,
3814 __u32 *pparmlen, __u32 *pdatalen)
3815{
3816 char *end_of_smb;
3817 __u32 data_count, data_offset, parm_count, parm_offset;
3818 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003819 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003820
3821 *pdatalen = 0;
3822 *pparmlen = 0;
3823
3824 if (buf == NULL)
3825 return -EINVAL;
3826
3827 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3828
Jeff Layton820a8032011-05-04 08:05:26 -04003829 bcc = get_bcc(&pSMBr->hdr);
3830 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003831 (char *)&pSMBr->ByteCount;
3832
3833 data_offset = le32_to_cpu(pSMBr->DataOffset);
3834 data_count = le32_to_cpu(pSMBr->DataCount);
3835 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3836 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3837
3838 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3839 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3840
3841 /* should we also check that parm and data areas do not overlap? */
3842 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003843 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003844 return -EINVAL;
3845 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003846 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003847 return -EINVAL;
3848 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003849 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003850 return -EINVAL;
3851 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003852 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3853 *ppdata, data_count, (data_count + *ppdata),
3854 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003855 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003856 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003857 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003858 return -EINVAL;
3859 }
3860 *pdatalen = data_count;
3861 *pparmlen = parm_count;
3862 return 0;
3863}
3864
Steve French0a4b92c2006-01-12 15:44:21 -08003865/* Get Security Descriptor (by handle) from remote server for a file or dir */
3866int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003867CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003868 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003869{
3870 int rc = 0;
3871 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003872 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003873 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003874 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003875
Joe Perchesf96637b2013-05-04 22:12:25 -05003876 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003877
Steve French630f3f0c2007-10-25 21:17:17 +00003878 *pbuflen = 0;
3879 *acl_inf = NULL;
3880
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003881 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003882 8 /* parm len */, tcon, (void **) &pSMB);
3883 if (rc)
3884 return rc;
3885
3886 pSMB->MaxParameterCount = cpu_to_le32(4);
3887 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3888 pSMB->MaxSetupCount = 0;
3889 pSMB->Fid = fid; /* file handle always le */
3890 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3891 CIFS_ACL_DACL);
3892 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003893 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003894 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003895 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003896
Steve Frencha761ac52007-10-18 21:45:27 +00003897 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003898 0, &rsp_iov);
3899 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003900 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003901 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003902 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003903 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003904 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003905 __u32 parm_len;
3906 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003907 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003908 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003909
3910/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003911 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003912 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003913 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003914 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003915 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003916
Joe Perchesf96637b2013-05-04 22:12:25 -05003917 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3918 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003919
3920 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3921 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003922 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003923 goto qsec_out;
3924 }
3925
3926/* BB check that data area is minimum length and as big as acl_len */
3927
Steve Frenchaf6f4612007-10-16 18:40:37 +00003928 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003929 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003930 cifs_dbg(VFS, "acl length %d does not match %d\n",
3931 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003932 if (*pbuflen > acl_len)
3933 *pbuflen = acl_len;
3934 }
Steve French0a4b92c2006-01-12 15:44:21 -08003935
Steve French630f3f0c2007-10-25 21:17:17 +00003936 /* check if buffer is big enough for the acl
3937 header followed by the smallest SID */
3938 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3939 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003940 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003941 rc = -EINVAL;
3942 *pbuflen = 0;
3943 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003944 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003945 if (*acl_inf == NULL) {
3946 *pbuflen = 0;
3947 rc = -ENOMEM;
3948 }
Steve French630f3f0c2007-10-25 21:17:17 +00003949 }
Steve French0a4b92c2006-01-12 15:44:21 -08003950 }
3951qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003952 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003953 return rc;
3954}
Steve French97837582007-12-31 07:47:21 +00003955
3956int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003957CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003958 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003959{
3960 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3961 int rc = 0;
3962 int bytes_returned = 0;
3963 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003964 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003965
3966setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003967 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003968 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003969 return rc;
Steve French97837582007-12-31 07:47:21 +00003970
3971 pSMB->MaxSetupCount = 0;
3972 pSMB->Reserved = 0;
3973
3974 param_count = 8;
3975 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3976 data_count = acllen;
3977 data_offset = param_offset + param_count;
3978 byte_count = 3 /* pad */ + param_count;
3979
3980 pSMB->DataCount = cpu_to_le32(data_count);
3981 pSMB->TotalDataCount = pSMB->DataCount;
3982 pSMB->MaxParameterCount = cpu_to_le32(4);
3983 pSMB->MaxDataCount = cpu_to_le32(16384);
3984 pSMB->ParameterCount = cpu_to_le32(param_count);
3985 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3986 pSMB->TotalParameterCount = pSMB->ParameterCount;
3987 pSMB->DataOffset = cpu_to_le32(data_offset);
3988 pSMB->SetupCount = 0;
3989 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3990 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3991
3992 pSMB->Fid = fid; /* file handle always le */
3993 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003994 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003995
3996 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003997 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3998 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003999 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004000 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004001 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004002
4003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4005
Joe Perchesf96637b2013-05-04 22:12:25 -05004006 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4007 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004008 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004009 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004010 cifs_buf_release(pSMB);
4011
4012 if (rc == -EAGAIN)
4013 goto setCifsAclRetry;
4014
4015 return (rc);
4016}
4017
Jeff Layton79df1ba2010-12-06 12:52:08 -05004018#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004019
Steve French6b8edfe2005-08-23 20:26:03 -07004020/* Legacy Query Path Information call for lookup to old servers such
4021 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004022int
4023SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4024 const char *search_name, FILE_ALL_INFO *data,
4025 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004026{
Steve Frenchad7a2922008-02-07 23:25:02 +00004027 QUERY_INFORMATION_REQ *pSMB;
4028 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004029 int rc = 0;
4030 int bytes_returned;
4031 int name_len;
4032
Joe Perchesf96637b2013-05-04 22:12:25 -05004033 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004034QInfRetry:
4035 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004036 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004037 if (rc)
4038 return rc;
4039
4040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4041 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004042 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004043 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004044 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004045 name_len++; /* trailing null */
4046 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004047 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004048 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004049 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004050 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004051 }
4052 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004053 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004054 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004055 pSMB->ByteCount = cpu_to_le16(name_len);
4056
4057 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004058 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004059 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004060 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004061 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004062 struct timespec ts;
4063 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004064
4065 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004066 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004067 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004068 ts.tv_nsec = 0;
4069 ts.tv_sec = time;
4070 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004071 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4072 data->LastWriteTime = data->ChangeTime;
4073 data->LastAccessTime = 0;
4074 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004075 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004076 data->EndOfFile = data->AllocationSize;
4077 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004078 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004079 } else
4080 rc = -EIO; /* bad buffer passed in */
4081
4082 cifs_buf_release(pSMB);
4083
4084 if (rc == -EAGAIN)
4085 goto QInfRetry;
4086
4087 return rc;
4088}
4089
Jeff Laytonbcd53572010-02-12 07:44:16 -05004090int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004091CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004092 u16 netfid, FILE_ALL_INFO *pFindData)
4093{
4094 struct smb_t2_qfi_req *pSMB = NULL;
4095 struct smb_t2_qfi_rsp *pSMBr = NULL;
4096 int rc = 0;
4097 int bytes_returned;
4098 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004099
Jeff Laytonbcd53572010-02-12 07:44:16 -05004100QFileInfoRetry:
4101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4102 (void **) &pSMBr);
4103 if (rc)
4104 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004105
Jeff Laytonbcd53572010-02-12 07:44:16 -05004106 params = 2 /* level */ + 2 /* fid */;
4107 pSMB->t2.TotalDataCount = 0;
4108 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4109 /* BB find exact max data count below from sess structure BB */
4110 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4111 pSMB->t2.MaxSetupCount = 0;
4112 pSMB->t2.Reserved = 0;
4113 pSMB->t2.Flags = 0;
4114 pSMB->t2.Timeout = 0;
4115 pSMB->t2.Reserved2 = 0;
4116 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4117 Fid) - 4);
4118 pSMB->t2.DataCount = 0;
4119 pSMB->t2.DataOffset = 0;
4120 pSMB->t2.SetupCount = 1;
4121 pSMB->t2.Reserved3 = 0;
4122 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4123 byte_count = params + 1 /* pad */ ;
4124 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4125 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4126 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4127 pSMB->Pad = 0;
4128 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004129 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004130 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004131
4132 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4133 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4134 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004135 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004136 } else { /* decode response */
4137 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4138
4139 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4140 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004141 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004142 rc = -EIO; /* bad smb */
4143 else if (pFindData) {
4144 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4145 memcpy((char *) pFindData,
4146 (char *) &pSMBr->hdr.Protocol +
4147 data_offset, sizeof(FILE_ALL_INFO));
4148 } else
4149 rc = -ENOMEM;
4150 }
4151 cifs_buf_release(pSMB);
4152 if (rc == -EAGAIN)
4153 goto QFileInfoRetry;
4154
4155 return rc;
4156}
Steve French6b8edfe2005-08-23 20:26:03 -07004157
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004159CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004160 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004161 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004162 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004164 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 TRANSACTION2_QPI_REQ *pSMB = NULL;
4166 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4167 int rc = 0;
4168 int bytes_returned;
4169 int name_len;
4170 __u16 params, byte_count;
4171
Joe Perchesf96637b2013-05-04 22:12:25 -05004172 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173QPathInfoRetry:
4174 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4175 (void **) &pSMBr);
4176 if (rc)
4177 return rc;
4178
4179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4180 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004181 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004182 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 name_len++; /* trailing null */
4184 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004185 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004186 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004188 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 }
4190
Steve French50c2f752007-07-13 00:33:32 +00004191 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 pSMB->TotalDataCount = 0;
4193 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004194 /* BB find exact max SMB PDU from sess structure BB */
4195 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 pSMB->MaxSetupCount = 0;
4197 pSMB->Reserved = 0;
4198 pSMB->Flags = 0;
4199 pSMB->Timeout = 0;
4200 pSMB->Reserved2 = 0;
4201 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004202 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 pSMB->DataCount = 0;
4204 pSMB->DataOffset = 0;
4205 pSMB->SetupCount = 1;
4206 pSMB->Reserved3 = 0;
4207 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4208 byte_count = params + 1 /* pad */ ;
4209 pSMB->TotalParameterCount = cpu_to_le16(params);
4210 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004211 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004212 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4213 else
4214 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004216 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 pSMB->ByteCount = cpu_to_le16(byte_count);
4218
4219 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4220 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4221 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004222 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 } else { /* decode response */
4224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4225
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004226 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4227 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004228 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004230 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004231 rc = -EIO; /* 24 or 26 expected but we do not read
4232 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004233 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004234 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004236
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004237 /*
4238 * On legacy responses we do not read the last field,
4239 * EAsize, fortunately since it varies by subdialect and
4240 * also note it differs on Set vs Get, ie two bytes or 4
4241 * bytes depending but we don't care here.
4242 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004243 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004244 size = sizeof(FILE_INFO_STANDARD);
4245 else
4246 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004247 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004248 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 } else
4250 rc = -ENOMEM;
4251 }
4252 cifs_buf_release(pSMB);
4253 if (rc == -EAGAIN)
4254 goto QPathInfoRetry;
4255
4256 return rc;
4257}
4258
4259int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004260CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004261 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4262{
4263 struct smb_t2_qfi_req *pSMB = NULL;
4264 struct smb_t2_qfi_rsp *pSMBr = NULL;
4265 int rc = 0;
4266 int bytes_returned;
4267 __u16 params, byte_count;
4268
4269UnixQFileInfoRetry:
4270 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4271 (void **) &pSMBr);
4272 if (rc)
4273 return rc;
4274
4275 params = 2 /* level */ + 2 /* fid */;
4276 pSMB->t2.TotalDataCount = 0;
4277 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4278 /* BB find exact max data count below from sess structure BB */
4279 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4280 pSMB->t2.MaxSetupCount = 0;
4281 pSMB->t2.Reserved = 0;
4282 pSMB->t2.Flags = 0;
4283 pSMB->t2.Timeout = 0;
4284 pSMB->t2.Reserved2 = 0;
4285 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4286 Fid) - 4);
4287 pSMB->t2.DataCount = 0;
4288 pSMB->t2.DataOffset = 0;
4289 pSMB->t2.SetupCount = 1;
4290 pSMB->t2.Reserved3 = 0;
4291 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4292 byte_count = params + 1 /* pad */ ;
4293 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4294 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4295 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4296 pSMB->Pad = 0;
4297 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004298 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004299 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004300
4301 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4302 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4303 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004304 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004305 } else { /* decode response */
4306 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4307
Jeff Layton820a8032011-05-04 08:05:26 -04004308 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004309 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 -05004310 rc = -EIO; /* bad smb */
4311 } else {
4312 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4313 memcpy((char *) pFindData,
4314 (char *) &pSMBr->hdr.Protocol +
4315 data_offset,
4316 sizeof(FILE_UNIX_BASIC_INFO));
4317 }
4318 }
4319
4320 cifs_buf_release(pSMB);
4321 if (rc == -EAGAIN)
4322 goto UnixQFileInfoRetry;
4323
4324 return rc;
4325}
4326
4327int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004328CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004330 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004331 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332{
4333/* SMB_QUERY_FILE_UNIX_BASIC */
4334 TRANSACTION2_QPI_REQ *pSMB = NULL;
4335 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4336 int rc = 0;
4337 int bytes_returned = 0;
4338 int name_len;
4339 __u16 params, byte_count;
4340
Joe Perchesf96637b2013-05-04 22:12:25 -05004341 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342UnixQPathInfoRetry:
4343 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4344 (void **) &pSMBr);
4345 if (rc)
4346 return rc;
4347
4348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4349 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004350 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4351 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 name_len++; /* trailing null */
4353 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004354 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 name_len = strnlen(searchName, PATH_MAX);
4356 name_len++; /* trailing null */
4357 strncpy(pSMB->FileName, searchName, name_len);
4358 }
4359
Steve French50c2f752007-07-13 00:33:32 +00004360 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 pSMB->TotalDataCount = 0;
4362 pSMB->MaxParameterCount = cpu_to_le16(2);
4363 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004364 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 pSMB->MaxSetupCount = 0;
4366 pSMB->Reserved = 0;
4367 pSMB->Flags = 0;
4368 pSMB->Timeout = 0;
4369 pSMB->Reserved2 = 0;
4370 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004371 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 pSMB->DataCount = 0;
4373 pSMB->DataOffset = 0;
4374 pSMB->SetupCount = 1;
4375 pSMB->Reserved3 = 0;
4376 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4377 byte_count = params + 1 /* pad */ ;
4378 pSMB->TotalParameterCount = cpu_to_le16(params);
4379 pSMB->ParameterCount = pSMB->TotalParameterCount;
4380 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4381 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004382 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 pSMB->ByteCount = cpu_to_le16(byte_count);
4384
4385 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4386 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4387 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004388 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 } else { /* decode response */
4390 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4391
Jeff Layton820a8032011-05-04 08:05:26 -04004392 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004393 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 -07004394 rc = -EIO; /* bad smb */
4395 } else {
4396 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4397 memcpy((char *) pFindData,
4398 (char *) &pSMBr->hdr.Protocol +
4399 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004400 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 }
4402 }
4403 cifs_buf_release(pSMB);
4404 if (rc == -EAGAIN)
4405 goto UnixQPathInfoRetry;
4406
4407 return rc;
4408}
4409
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410/* xid, tcon, searchName and codepage are input parms, rest are returned */
4411int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004412CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004413 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004414 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004415 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416{
4417/* level 257 SMB_ */
4418 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4419 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004420 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 int rc = 0;
4422 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004423 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004425 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426
Joe Perchesf96637b2013-05-04 22:12:25 -05004427 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428
4429findFirstRetry:
4430 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4431 (void **) &pSMBr);
4432 if (rc)
4433 return rc;
4434
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004435 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004436 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004437
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4439 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004440 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4441 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004442 /* We can not add the asterik earlier in case
4443 it got remapped to 0xF03A as if it were part of the
4444 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004446 if (msearch) {
4447 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4448 pSMB->FileName[name_len+1] = 0;
4449 pSMB->FileName[name_len+2] = '*';
4450 pSMB->FileName[name_len+3] = 0;
4451 name_len += 4; /* now the trailing null */
4452 /* null terminate just in case */
4453 pSMB->FileName[name_len] = 0;
4454 pSMB->FileName[name_len+1] = 0;
4455 name_len += 2;
4456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 } else { /* BB add check for overrun of SMB buf BB */
4458 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004460 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 free buffer exit; BB */
4462 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004463 if (msearch) {
4464 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4465 pSMB->FileName[name_len+1] = '*';
4466 pSMB->FileName[name_len+2] = 0;
4467 name_len += 3;
4468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 }
4470
4471 params = 12 + name_len /* includes null */ ;
4472 pSMB->TotalDataCount = 0; /* no EAs */
4473 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004474 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 pSMB->MaxSetupCount = 0;
4476 pSMB->Reserved = 0;
4477 pSMB->Flags = 0;
4478 pSMB->Timeout = 0;
4479 pSMB->Reserved2 = 0;
4480 byte_count = params + 1 /* pad */ ;
4481 pSMB->TotalParameterCount = cpu_to_le16(params);
4482 pSMB->ParameterCount = pSMB->TotalParameterCount;
4483 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004484 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4485 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 pSMB->DataCount = 0;
4487 pSMB->DataOffset = 0;
4488 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4489 pSMB->Reserved3 = 0;
4490 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4491 pSMB->SearchAttributes =
4492 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4493 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004494 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004495 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4497
4498 /* BB what should we set StorageType to? Does it matter? BB */
4499 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004500 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 pSMB->ByteCount = cpu_to_le16(byte_count);
4502
4503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004505 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506
Steve French88274812006-03-09 22:21:45 +00004507 if (rc) {/* BB add logic to retry regular search if Unix search
4508 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004510 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004511
Steve French88274812006-03-09 22:21:45 +00004512 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
4514 /* BB eventually could optimize out free and realloc of buf */
4515 /* for this case */
4516 if (rc == -EAGAIN)
4517 goto findFirstRetry;
4518 } else { /* decode response */
4519 /* BB remember to free buffer if error BB */
4520 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004521 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004522 unsigned int lnoff;
4523
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004525 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 else
Steve French4b18f2a2008-04-29 00:06:05 +00004527 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
4529 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004530 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004531 psrch_inf->srch_entries_start =
4532 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4535 le16_to_cpu(pSMBr->t2.ParameterOffset));
4536
Steve French790fe572007-07-07 19:25:05 +00004537 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004538 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 else
Steve French4b18f2a2008-04-29 00:06:05 +00004540 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541
Steve French50c2f752007-07-13 00:33:32 +00004542 psrch_inf->entries_in_buffer =
4543 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004544 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004546 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004547 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004548 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004549 psrch_inf->last_entry = NULL;
4550 return rc;
4551 }
4552
Steve French0752f152008-10-07 20:03:33 +00004553 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004554 lnoff;
4555
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004556 if (pnetfid)
4557 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 } else {
4559 cifs_buf_release(pSMB);
4560 }
4561 }
4562
4563 return rc;
4564}
4565
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004566int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4567 __u16 searchHandle, __u16 search_flags,
4568 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569{
4570 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4571 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004572 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 char *response_data;
4574 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004575 int bytes_returned;
4576 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 __u16 params, byte_count;
4578
Joe Perchesf96637b2013-05-04 22:12:25 -05004579 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580
Steve French4b18f2a2008-04-29 00:06:05 +00004581 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 return -ENOENT;
4583
4584 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4585 (void **) &pSMBr);
4586 if (rc)
4587 return rc;
4588
Steve French50c2f752007-07-13 00:33:32 +00004589 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 byte_count = 0;
4591 pSMB->TotalDataCount = 0; /* no EAs */
4592 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004593 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 pSMB->MaxSetupCount = 0;
4595 pSMB->Reserved = 0;
4596 pSMB->Flags = 0;
4597 pSMB->Timeout = 0;
4598 pSMB->Reserved2 = 0;
4599 pSMB->ParameterOffset = cpu_to_le16(
4600 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4601 pSMB->DataCount = 0;
4602 pSMB->DataOffset = 0;
4603 pSMB->SetupCount = 1;
4604 pSMB->Reserved3 = 0;
4605 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4606 pSMB->SearchHandle = searchHandle; /* always kept as le */
4607 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004608 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4610 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004611 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612
4613 name_len = psrch_inf->resume_name_len;
4614 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004615 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4617 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004618 /* 14 byte parm len above enough for 2 byte null terminator */
4619 pSMB->ResumeFileName[name_len] = 0;
4620 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 } else {
4622 rc = -EINVAL;
4623 goto FNext2_err_exit;
4624 }
4625 byte_count = params + 1 /* pad */ ;
4626 pSMB->TotalParameterCount = cpu_to_le16(params);
4627 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004628 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004630
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004633 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 if (rc) {
4635 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004636 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004637 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004638 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004640 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 } else { /* decode response */
4642 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004643
Steve French790fe572007-07-07 19:25:05 +00004644 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004645 unsigned int lnoff;
4646
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 /* BB fixme add lock for file (srch_info) struct here */
4648 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004649 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 else
Steve French4b18f2a2008-04-29 00:06:05 +00004651 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 response_data = (char *) &pSMBr->hdr.Protocol +
4653 le16_to_cpu(pSMBr->t2.ParameterOffset);
4654 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4655 response_data = (char *)&pSMBr->hdr.Protocol +
4656 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004657 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004658 cifs_small_buf_release(
4659 psrch_inf->ntwrk_buf_start);
4660 else
4661 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 psrch_inf->srch_entries_start = response_data;
4663 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004664 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004665 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004666 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 else
Steve French4b18f2a2008-04-29 00:06:05 +00004668 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004669 psrch_inf->entries_in_buffer =
4670 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 psrch_inf->index_of_last_entry +=
4672 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004673 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004674 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004675 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004676 psrch_inf->last_entry = NULL;
4677 return rc;
4678 } else
4679 psrch_inf->last_entry =
4680 psrch_inf->srch_entries_start + lnoff;
4681
Joe Perchesf96637b2013-05-04 22:12:25 -05004682/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4683 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684
4685 /* BB fixme add unlock here */
4686 }
4687
4688 }
4689
4690 /* BB On error, should we leave previous search buf (and count and
4691 last entry fields) intact or free the previous one? */
4692
4693 /* Note: On -EAGAIN error only caller can retry on handle based calls
4694 since file handle passed in no longer valid */
4695FNext2_err_exit:
4696 if (rc != 0)
4697 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 return rc;
4699}
4700
4701int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004702CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004703 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704{
4705 int rc = 0;
4706 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707
Joe Perchesf96637b2013-05-04 22:12:25 -05004708 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4710
4711 /* no sense returning error if session restarted
4712 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004713 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 return 0;
4715 if (rc)
4716 return rc;
4717
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 pSMB->FileID = searchHandle;
4719 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004720 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004721 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004722 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004723 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004724
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004725 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726
4727 /* Since session is dead, search handle closed on server already */
4728 if (rc == -EAGAIN)
4729 rc = 0;
4730
4731 return rc;
4732}
4733
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004735CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004736 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004737 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738{
4739 int rc = 0;
4740 TRANSACTION2_QPI_REQ *pSMB = NULL;
4741 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4742 int name_len, bytes_returned;
4743 __u16 params, byte_count;
4744
Joe Perchesf96637b2013-05-04 22:12:25 -05004745 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004746 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004747 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
4749GetInodeNumberRetry:
4750 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004751 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 if (rc)
4753 return rc;
4754
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4756 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004757 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004758 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004759 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 name_len++; /* trailing null */
4761 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004762 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004763 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004765 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 }
4767
4768 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4769 pSMB->TotalDataCount = 0;
4770 pSMB->MaxParameterCount = cpu_to_le16(2);
4771 /* BB find exact max data count below from sess structure BB */
4772 pSMB->MaxDataCount = cpu_to_le16(4000);
4773 pSMB->MaxSetupCount = 0;
4774 pSMB->Reserved = 0;
4775 pSMB->Flags = 0;
4776 pSMB->Timeout = 0;
4777 pSMB->Reserved2 = 0;
4778 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004779 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 pSMB->DataCount = 0;
4781 pSMB->DataOffset = 0;
4782 pSMB->SetupCount = 1;
4783 pSMB->Reserved3 = 0;
4784 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4785 byte_count = params + 1 /* pad */ ;
4786 pSMB->TotalParameterCount = cpu_to_le16(params);
4787 pSMB->ParameterCount = pSMB->TotalParameterCount;
4788 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4789 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004790 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 pSMB->ByteCount = cpu_to_le16(byte_count);
4792
4793 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4794 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4795 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004796 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 } else {
4798 /* decode response */
4799 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004801 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 /* If rc should we check for EOPNOSUPP and
4803 disable the srvino flag? or in caller? */
4804 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004805 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4807 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004808 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004810 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004811 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 rc = -EIO;
4813 goto GetInodeNumOut;
4814 }
4815 pfinfo = (struct file_internal_info *)
4816 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004817 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 }
4819 }
4820GetInodeNumOut:
4821 cifs_buf_release(pSMB);
4822 if (rc == -EAGAIN)
4823 goto GetInodeNumberRetry;
4824 return rc;
4825}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826
4827int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004828CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004829 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004830 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004831 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832{
4833/* TRANS2_GET_DFS_REFERRAL */
4834 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4835 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 int rc = 0;
4837 int bytes_returned;
4838 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004840 *num_of_nodes = 0;
4841 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842
Joe Perchesf96637b2013-05-04 22:12:25 -05004843 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004844 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004846
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004848 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 (void **) &pSMBr);
4850 if (rc)
4851 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004852
4853 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004854 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004855 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004856 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004858 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004860 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862
4863 if (ses->capabilities & CAP_UNICODE) {
4864 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4865 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004866 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004867 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004868 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 name_len++; /* trailing null */
4870 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004871 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004872 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004874 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 }
4876
Dan Carpenter65c3b202015-04-30 17:30:24 +03004877 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004878 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004879
Steve French50c2f752007-07-13 00:33:32 +00004880 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004881
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 params = 2 /* level */ + name_len /*includes null */ ;
4883 pSMB->TotalDataCount = 0;
4884 pSMB->DataCount = 0;
4885 pSMB->DataOffset = 0;
4886 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004887 /* BB find exact max SMB PDU from sess structure BB */
4888 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 pSMB->MaxSetupCount = 0;
4890 pSMB->Reserved = 0;
4891 pSMB->Flags = 0;
4892 pSMB->Timeout = 0;
4893 pSMB->Reserved2 = 0;
4894 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004895 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 pSMB->SetupCount = 1;
4897 pSMB->Reserved3 = 0;
4898 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4899 byte_count = params + 3 /* pad */ ;
4900 pSMB->ParameterCount = cpu_to_le16(params);
4901 pSMB->TotalParameterCount = pSMB->ParameterCount;
4902 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004903 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 pSMB->ByteCount = cpu_to_le16(byte_count);
4905
4906 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4908 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004909 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004910 goto GetDFSRefExit;
4911 }
4912 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004914 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004915 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004916 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004917 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004919
Joe Perchesf96637b2013-05-04 22:12:25 -05004920 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4921 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004922
4923 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004924 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4925 le16_to_cpu(pSMBr->t2.DataCount),
4926 num_of_nodes, target_nodes, nls_codepage,
4927 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004928 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004929
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004931 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932
4933 if (rc == -EAGAIN)
4934 goto getDFSRetry;
4935
4936 return rc;
4937}
4938
Steve French20962432005-09-21 22:05:57 -07004939/* Query File System Info such as free space to old servers such as Win 9x */
4940int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004941SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4942 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004943{
4944/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4945 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4946 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4947 FILE_SYSTEM_ALLOC_INFO *response_data;
4948 int rc = 0;
4949 int bytes_returned = 0;
4950 __u16 params, byte_count;
4951
Joe Perchesf96637b2013-05-04 22:12:25 -05004952 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004953oldQFSInfoRetry:
4954 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4955 (void **) &pSMBr);
4956 if (rc)
4957 return rc;
Steve French20962432005-09-21 22:05:57 -07004958
4959 params = 2; /* level */
4960 pSMB->TotalDataCount = 0;
4961 pSMB->MaxParameterCount = cpu_to_le16(2);
4962 pSMB->MaxDataCount = cpu_to_le16(1000);
4963 pSMB->MaxSetupCount = 0;
4964 pSMB->Reserved = 0;
4965 pSMB->Flags = 0;
4966 pSMB->Timeout = 0;
4967 pSMB->Reserved2 = 0;
4968 byte_count = params + 1 /* pad */ ;
4969 pSMB->TotalParameterCount = cpu_to_le16(params);
4970 pSMB->ParameterCount = pSMB->TotalParameterCount;
4971 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4972 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4973 pSMB->DataCount = 0;
4974 pSMB->DataOffset = 0;
4975 pSMB->SetupCount = 1;
4976 pSMB->Reserved3 = 0;
4977 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4978 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004979 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004980 pSMB->ByteCount = cpu_to_le16(byte_count);
4981
4982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4984 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004985 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004986 } else { /* decode response */
4987 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4988
Jeff Layton820a8032011-05-04 08:05:26 -04004989 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004990 rc = -EIO; /* bad smb */
4991 else {
4992 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004993 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004994 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004995
Steve French50c2f752007-07-13 00:33:32 +00004996 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004997 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4998 FSData->f_bsize =
4999 le16_to_cpu(response_data->BytesPerSector) *
5000 le32_to_cpu(response_data->
5001 SectorsPerAllocationUnit);
5002 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005003 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005004 FSData->f_bfree = FSData->f_bavail =
5005 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005006 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5007 (unsigned long long)FSData->f_blocks,
5008 (unsigned long long)FSData->f_bfree,
5009 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005010 }
5011 }
5012 cifs_buf_release(pSMB);
5013
5014 if (rc == -EAGAIN)
5015 goto oldQFSInfoRetry;
5016
5017 return rc;
5018}
5019
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005021CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5022 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023{
5024/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5025 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5026 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5027 FILE_SYSTEM_INFO *response_data;
5028 int rc = 0;
5029 int bytes_returned = 0;
5030 __u16 params, byte_count;
5031
Joe Perchesf96637b2013-05-04 22:12:25 -05005032 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033QFSInfoRetry:
5034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5035 (void **) &pSMBr);
5036 if (rc)
5037 return rc;
5038
5039 params = 2; /* level */
5040 pSMB->TotalDataCount = 0;
5041 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005042 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 pSMB->MaxSetupCount = 0;
5044 pSMB->Reserved = 0;
5045 pSMB->Flags = 0;
5046 pSMB->Timeout = 0;
5047 pSMB->Reserved2 = 0;
5048 byte_count = params + 1 /* pad */ ;
5049 pSMB->TotalParameterCount = cpu_to_le16(params);
5050 pSMB->ParameterCount = pSMB->TotalParameterCount;
5051 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005052 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 pSMB->DataCount = 0;
5054 pSMB->DataOffset = 0;
5055 pSMB->SetupCount = 1;
5056 pSMB->Reserved3 = 0;
5057 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5058 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005059 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 pSMB->ByteCount = cpu_to_le16(byte_count);
5061
5062 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5063 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5064 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005065 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005067 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068
Jeff Layton820a8032011-05-04 08:05:26 -04005069 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 rc = -EIO; /* bad smb */
5071 else {
5072 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073
5074 response_data =
5075 (FILE_SYSTEM_INFO
5076 *) (((char *) &pSMBr->hdr.Protocol) +
5077 data_offset);
5078 FSData->f_bsize =
5079 le32_to_cpu(response_data->BytesPerSector) *
5080 le32_to_cpu(response_data->
5081 SectorsPerAllocationUnit);
5082 FSData->f_blocks =
5083 le64_to_cpu(response_data->TotalAllocationUnits);
5084 FSData->f_bfree = FSData->f_bavail =
5085 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005086 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5087 (unsigned long long)FSData->f_blocks,
5088 (unsigned long long)FSData->f_bfree,
5089 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 }
5091 }
5092 cifs_buf_release(pSMB);
5093
5094 if (rc == -EAGAIN)
5095 goto QFSInfoRetry;
5096
5097 return rc;
5098}
5099
5100int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005101CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102{
5103/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5104 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5105 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5106 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5107 int rc = 0;
5108 int bytes_returned = 0;
5109 __u16 params, byte_count;
5110
Joe Perchesf96637b2013-05-04 22:12:25 -05005111 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112QFSAttributeRetry:
5113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5114 (void **) &pSMBr);
5115 if (rc)
5116 return rc;
5117
5118 params = 2; /* level */
5119 pSMB->TotalDataCount = 0;
5120 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005121 /* BB find exact max SMB PDU from sess structure BB */
5122 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 pSMB->MaxSetupCount = 0;
5124 pSMB->Reserved = 0;
5125 pSMB->Flags = 0;
5126 pSMB->Timeout = 0;
5127 pSMB->Reserved2 = 0;
5128 byte_count = params + 1 /* pad */ ;
5129 pSMB->TotalParameterCount = cpu_to_le16(params);
5130 pSMB->ParameterCount = pSMB->TotalParameterCount;
5131 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005132 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 pSMB->DataCount = 0;
5134 pSMB->DataOffset = 0;
5135 pSMB->SetupCount = 1;
5136 pSMB->Reserved3 = 0;
5137 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5138 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005139 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 pSMB->ByteCount = cpu_to_le16(byte_count);
5141
5142 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5143 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5144 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005145 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 } else { /* decode response */
5147 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5148
Jeff Layton820a8032011-05-04 08:05:26 -04005149 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005150 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 rc = -EIO; /* bad smb */
5152 } else {
5153 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5154 response_data =
5155 (FILE_SYSTEM_ATTRIBUTE_INFO
5156 *) (((char *) &pSMBr->hdr.Protocol) +
5157 data_offset);
5158 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005159 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 }
5161 }
5162 cifs_buf_release(pSMB);
5163
5164 if (rc == -EAGAIN)
5165 goto QFSAttributeRetry;
5166
5167 return rc;
5168}
5169
5170int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005171CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172{
5173/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5174 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5175 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5176 FILE_SYSTEM_DEVICE_INFO *response_data;
5177 int rc = 0;
5178 int bytes_returned = 0;
5179 __u16 params, byte_count;
5180
Joe Perchesf96637b2013-05-04 22:12:25 -05005181 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182QFSDeviceRetry:
5183 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5184 (void **) &pSMBr);
5185 if (rc)
5186 return rc;
5187
5188 params = 2; /* level */
5189 pSMB->TotalDataCount = 0;
5190 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005191 /* BB find exact max SMB PDU from sess structure BB */
5192 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 pSMB->MaxSetupCount = 0;
5194 pSMB->Reserved = 0;
5195 pSMB->Flags = 0;
5196 pSMB->Timeout = 0;
5197 pSMB->Reserved2 = 0;
5198 byte_count = params + 1 /* pad */ ;
5199 pSMB->TotalParameterCount = cpu_to_le16(params);
5200 pSMB->ParameterCount = pSMB->TotalParameterCount;
5201 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005202 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203
5204 pSMB->DataCount = 0;
5205 pSMB->DataOffset = 0;
5206 pSMB->SetupCount = 1;
5207 pSMB->Reserved3 = 0;
5208 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5209 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005210 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 pSMB->ByteCount = cpu_to_le16(byte_count);
5212
5213 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5214 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5215 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005216 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 } else { /* decode response */
5218 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5219
Jeff Layton820a8032011-05-04 08:05:26 -04005220 if (rc || get_bcc(&pSMBr->hdr) <
5221 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 rc = -EIO; /* bad smb */
5223 else {
5224 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5225 response_data =
Steve French737b7582005-04-28 22:41:06 -07005226 (FILE_SYSTEM_DEVICE_INFO *)
5227 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 data_offset);
5229 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005230 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 }
5232 }
5233 cifs_buf_release(pSMB);
5234
5235 if (rc == -EAGAIN)
5236 goto QFSDeviceRetry;
5237
5238 return rc;
5239}
5240
5241int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005242CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243{
5244/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5245 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5246 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5247 FILE_SYSTEM_UNIX_INFO *response_data;
5248 int rc = 0;
5249 int bytes_returned = 0;
5250 __u16 params, byte_count;
5251
Joe Perchesf96637b2013-05-04 22:12:25 -05005252 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005254 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5255 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 if (rc)
5257 return rc;
5258
5259 params = 2; /* level */
5260 pSMB->TotalDataCount = 0;
5261 pSMB->DataCount = 0;
5262 pSMB->DataOffset = 0;
5263 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005264 /* BB find exact max SMB PDU from sess structure BB */
5265 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 pSMB->MaxSetupCount = 0;
5267 pSMB->Reserved = 0;
5268 pSMB->Flags = 0;
5269 pSMB->Timeout = 0;
5270 pSMB->Reserved2 = 0;
5271 byte_count = params + 1 /* pad */ ;
5272 pSMB->ParameterCount = cpu_to_le16(params);
5273 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005274 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5275 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 pSMB->SetupCount = 1;
5277 pSMB->Reserved3 = 0;
5278 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5279 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005280 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 pSMB->ByteCount = cpu_to_le16(byte_count);
5282
5283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5285 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005286 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 } else { /* decode response */
5288 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5289
Jeff Layton820a8032011-05-04 08:05:26 -04005290 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 rc = -EIO; /* bad smb */
5292 } else {
5293 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5294 response_data =
5295 (FILE_SYSTEM_UNIX_INFO
5296 *) (((char *) &pSMBr->hdr.Protocol) +
5297 data_offset);
5298 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005299 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 }
5301 }
5302 cifs_buf_release(pSMB);
5303
5304 if (rc == -EAGAIN)
5305 goto QFSUnixRetry;
5306
5307
5308 return rc;
5309}
5310
Jeremy Allisonac670552005-06-22 17:26:35 -07005311int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005312CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005313{
5314/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5315 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5316 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5317 int rc = 0;
5318 int bytes_returned = 0;
5319 __u16 params, param_offset, offset, byte_count;
5320
Joe Perchesf96637b2013-05-04 22:12:25 -05005321 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005322SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005323 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005324 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5325 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005326 if (rc)
5327 return rc;
5328
5329 params = 4; /* 2 bytes zero followed by info level. */
5330 pSMB->MaxSetupCount = 0;
5331 pSMB->Reserved = 0;
5332 pSMB->Flags = 0;
5333 pSMB->Timeout = 0;
5334 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005335 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5336 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005337 offset = param_offset + params;
5338
5339 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005340 /* BB find exact max SMB PDU from sess structure BB */
5341 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005342 pSMB->SetupCount = 1;
5343 pSMB->Reserved3 = 0;
5344 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5345 byte_count = 1 /* pad */ + params + 12;
5346
5347 pSMB->DataCount = cpu_to_le16(12);
5348 pSMB->ParameterCount = cpu_to_le16(params);
5349 pSMB->TotalDataCount = pSMB->DataCount;
5350 pSMB->TotalParameterCount = pSMB->ParameterCount;
5351 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5352 pSMB->DataOffset = cpu_to_le16(offset);
5353
5354 /* Params. */
5355 pSMB->FileNum = 0;
5356 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5357
5358 /* Data. */
5359 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5360 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5361 pSMB->ClientUnixCap = cpu_to_le64(cap);
5362
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005363 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005364 pSMB->ByteCount = cpu_to_le16(byte_count);
5365
5366 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5367 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5368 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005369 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005370 } else { /* decode response */
5371 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005372 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005373 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005374 }
5375 cifs_buf_release(pSMB);
5376
5377 if (rc == -EAGAIN)
5378 goto SETFSUnixRetry;
5379
5380 return rc;
5381}
5382
5383
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384
5385int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005386CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005387 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388{
5389/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5390 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5391 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5392 FILE_SYSTEM_POSIX_INFO *response_data;
5393 int rc = 0;
5394 int bytes_returned = 0;
5395 __u16 params, byte_count;
5396
Joe Perchesf96637b2013-05-04 22:12:25 -05005397 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398QFSPosixRetry:
5399 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5400 (void **) &pSMBr);
5401 if (rc)
5402 return rc;
5403
5404 params = 2; /* level */
5405 pSMB->TotalDataCount = 0;
5406 pSMB->DataCount = 0;
5407 pSMB->DataOffset = 0;
5408 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005409 /* BB find exact max SMB PDU from sess structure BB */
5410 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 pSMB->MaxSetupCount = 0;
5412 pSMB->Reserved = 0;
5413 pSMB->Flags = 0;
5414 pSMB->Timeout = 0;
5415 pSMB->Reserved2 = 0;
5416 byte_count = params + 1 /* pad */ ;
5417 pSMB->ParameterCount = cpu_to_le16(params);
5418 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005419 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5420 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 pSMB->SetupCount = 1;
5422 pSMB->Reserved3 = 0;
5423 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5424 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005425 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 pSMB->ByteCount = cpu_to_le16(byte_count);
5427
5428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5430 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005431 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 } else { /* decode response */
5433 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5434
Jeff Layton820a8032011-05-04 08:05:26 -04005435 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 rc = -EIO; /* bad smb */
5437 } else {
5438 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5439 response_data =
5440 (FILE_SYSTEM_POSIX_INFO
5441 *) (((char *) &pSMBr->hdr.Protocol) +
5442 data_offset);
5443 FSData->f_bsize =
5444 le32_to_cpu(response_data->BlockSize);
5445 FSData->f_blocks =
5446 le64_to_cpu(response_data->TotalBlocks);
5447 FSData->f_bfree =
5448 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005449 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 FSData->f_bavail = FSData->f_bfree;
5451 } else {
5452 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005453 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 }
Steve French790fe572007-07-07 19:25:05 +00005455 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005457 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005458 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005460 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 }
5462 }
5463 cifs_buf_release(pSMB);
5464
5465 if (rc == -EAGAIN)
5466 goto QFSPosixRetry;
5467
5468 return rc;
5469}
5470
5471
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005472/*
5473 * We can not use write of zero bytes trick to set file size due to need for
5474 * large file support. Also note that this SetPathInfo is preferred to
5475 * SetFileInfo based method in next routine which is only needed to work around
5476 * a sharing violation bugin Samba which this routine can run into.
5477 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005479CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005480 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5481 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482{
5483 struct smb_com_transaction2_spi_req *pSMB = NULL;
5484 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5485 struct file_end_of_file_info *parm_data;
5486 int name_len;
5487 int rc = 0;
5488 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005489 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005490
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 __u16 params, byte_count, data_count, param_offset, offset;
5492
Joe Perchesf96637b2013-05-04 22:12:25 -05005493 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494SetEOFRetry:
5495 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5496 (void **) &pSMBr);
5497 if (rc)
5498 return rc;
5499
5500 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5501 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005502 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5503 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 name_len++; /* trailing null */
5505 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005506 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005507 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005509 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 }
5511 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005512 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005514 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 pSMB->MaxSetupCount = 0;
5516 pSMB->Reserved = 0;
5517 pSMB->Flags = 0;
5518 pSMB->Timeout = 0;
5519 pSMB->Reserved2 = 0;
5520 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005521 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005523 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005524 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5525 pSMB->InformationLevel =
5526 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5527 else
5528 pSMB->InformationLevel =
5529 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5530 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5532 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005533 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 else
5535 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005536 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 }
5538
5539 parm_data =
5540 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5541 offset);
5542 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5543 pSMB->DataOffset = cpu_to_le16(offset);
5544 pSMB->SetupCount = 1;
5545 pSMB->Reserved3 = 0;
5546 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5547 byte_count = 3 /* pad */ + params + data_count;
5548 pSMB->DataCount = cpu_to_le16(data_count);
5549 pSMB->TotalDataCount = pSMB->DataCount;
5550 pSMB->ParameterCount = cpu_to_le16(params);
5551 pSMB->TotalParameterCount = pSMB->ParameterCount;
5552 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005553 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 parm_data->FileSize = cpu_to_le64(size);
5555 pSMB->ByteCount = cpu_to_le16(byte_count);
5556 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5557 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005558 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005559 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560
5561 cifs_buf_release(pSMB);
5562
5563 if (rc == -EAGAIN)
5564 goto SetEOFRetry;
5565
5566 return rc;
5567}
5568
5569int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005570CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5571 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572{
5573 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 struct file_end_of_file_info *parm_data;
5575 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 __u16 params, param_offset, offset, byte_count, count;
5577
Joe Perchesf96637b2013-05-04 22:12:25 -05005578 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5579 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005580 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5581
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 if (rc)
5583 return rc;
5584
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005585 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5586 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005587
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 params = 6;
5589 pSMB->MaxSetupCount = 0;
5590 pSMB->Reserved = 0;
5591 pSMB->Flags = 0;
5592 pSMB->Timeout = 0;
5593 pSMB->Reserved2 = 0;
5594 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5595 offset = param_offset + params;
5596
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 count = sizeof(struct file_end_of_file_info);
5598 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005599 /* BB find exact max SMB PDU from sess structure BB */
5600 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 pSMB->SetupCount = 1;
5602 pSMB->Reserved3 = 0;
5603 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5604 byte_count = 3 /* pad */ + params + count;
5605 pSMB->DataCount = cpu_to_le16(count);
5606 pSMB->ParameterCount = cpu_to_le16(params);
5607 pSMB->TotalDataCount = pSMB->DataCount;
5608 pSMB->TotalParameterCount = pSMB->ParameterCount;
5609 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5610 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005611 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5612 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 pSMB->DataOffset = cpu_to_le16(offset);
5614 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005615 pSMB->Fid = cfile->fid.netfid;
5616 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5618 pSMB->InformationLevel =
5619 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5620 else
5621 pSMB->InformationLevel =
5622 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005623 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5625 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005626 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 else
5628 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005629 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 }
5631 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005632 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005634 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005635 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005637 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5638 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 }
5640
Steve French50c2f752007-07-13 00:33:32 +00005641 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 since file handle passed in no longer valid */
5643
5644 return rc;
5645}
5646
Steve French50c2f752007-07-13 00:33:32 +00005647/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 an open handle, rather than by pathname - this is awkward due to
5649 potential access conflicts on the open, but it is unavoidable for these
5650 old servers since the only other choice is to go from 100 nanosecond DCE
5651 time and resort to the original setpathinfo level which takes the ancient
5652 DOS time format with 2 second granularity */
5653int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005654CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005655 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656{
5657 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 char *data_offset;
5659 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 __u16 params, param_offset, offset, byte_count, count;
5661
Joe Perchesf96637b2013-05-04 22:12:25 -05005662 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005663 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5664
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 if (rc)
5666 return rc;
5667
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005668 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5669 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005670
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 params = 6;
5672 pSMB->MaxSetupCount = 0;
5673 pSMB->Reserved = 0;
5674 pSMB->Flags = 0;
5675 pSMB->Timeout = 0;
5676 pSMB->Reserved2 = 0;
5677 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5678 offset = param_offset + params;
5679
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005680 data_offset = (char *)pSMB +
5681 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682
Steve French26f57362007-08-30 22:09:15 +00005683 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005685 /* BB find max SMB PDU from sess */
5686 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 pSMB->SetupCount = 1;
5688 pSMB->Reserved3 = 0;
5689 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5690 byte_count = 3 /* pad */ + params + count;
5691 pSMB->DataCount = cpu_to_le16(count);
5692 pSMB->ParameterCount = cpu_to_le16(params);
5693 pSMB->TotalDataCount = pSMB->DataCount;
5694 pSMB->TotalParameterCount = pSMB->ParameterCount;
5695 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5696 pSMB->DataOffset = cpu_to_le16(offset);
5697 pSMB->Fid = fid;
5698 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5699 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5700 else
5701 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5702 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005703 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005705 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005706 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005707 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005708 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005709 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5710 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711
Steve French50c2f752007-07-13 00:33:32 +00005712 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713 since file handle passed in no longer valid */
5714
5715 return rc;
5716}
5717
Jeff Layton6d22f092008-09-23 11:48:35 -04005718int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005719CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005720 bool delete_file, __u16 fid, __u32 pid_of_opener)
5721{
5722 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5723 char *data_offset;
5724 int rc = 0;
5725 __u16 params, param_offset, offset, byte_count, count;
5726
Joe Perchesf96637b2013-05-04 22:12:25 -05005727 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005728 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5729
5730 if (rc)
5731 return rc;
5732
5733 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5734 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5735
5736 params = 6;
5737 pSMB->MaxSetupCount = 0;
5738 pSMB->Reserved = 0;
5739 pSMB->Flags = 0;
5740 pSMB->Timeout = 0;
5741 pSMB->Reserved2 = 0;
5742 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5743 offset = param_offset + params;
5744
5745 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5746
5747 count = 1;
5748 pSMB->MaxParameterCount = cpu_to_le16(2);
5749 /* BB find max SMB PDU from sess */
5750 pSMB->MaxDataCount = cpu_to_le16(1000);
5751 pSMB->SetupCount = 1;
5752 pSMB->Reserved3 = 0;
5753 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5754 byte_count = 3 /* pad */ + params + count;
5755 pSMB->DataCount = cpu_to_le16(count);
5756 pSMB->ParameterCount = cpu_to_le16(params);
5757 pSMB->TotalDataCount = pSMB->DataCount;
5758 pSMB->TotalParameterCount = pSMB->ParameterCount;
5759 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5760 pSMB->DataOffset = cpu_to_le16(offset);
5761 pSMB->Fid = fid;
5762 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5763 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005764 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005765 pSMB->ByteCount = cpu_to_le16(byte_count);
5766 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005767 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005768 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005769 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005770 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005771
5772 return rc;
5773}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
5775int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005776CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005777 const char *fileName, const FILE_BASIC_INFO *data,
5778 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779{
5780 TRANSACTION2_SPI_REQ *pSMB = NULL;
5781 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5782 int name_len;
5783 int rc = 0;
5784 int bytes_returned = 0;
5785 char *data_offset;
5786 __u16 params, param_offset, offset, byte_count, count;
5787
Joe Perchesf96637b2013-05-04 22:12:25 -05005788 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
5790SetTimesRetry:
5791 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5792 (void **) &pSMBr);
5793 if (rc)
5794 return rc;
5795
5796 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5797 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005798 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5799 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 name_len++; /* trailing null */
5801 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005802 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803 name_len = strnlen(fileName, PATH_MAX);
5804 name_len++; /* trailing null */
5805 strncpy(pSMB->FileName, fileName, name_len);
5806 }
5807
5808 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005809 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005811 /* BB find max SMB PDU from sess structure BB */
5812 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813 pSMB->MaxSetupCount = 0;
5814 pSMB->Reserved = 0;
5815 pSMB->Flags = 0;
5816 pSMB->Timeout = 0;
5817 pSMB->Reserved2 = 0;
5818 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005819 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 offset = param_offset + params;
5821 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5822 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5823 pSMB->DataOffset = cpu_to_le16(offset);
5824 pSMB->SetupCount = 1;
5825 pSMB->Reserved3 = 0;
5826 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5827 byte_count = 3 /* pad */ + params + count;
5828
5829 pSMB->DataCount = cpu_to_le16(count);
5830 pSMB->ParameterCount = cpu_to_le16(params);
5831 pSMB->TotalDataCount = pSMB->DataCount;
5832 pSMB->TotalParameterCount = pSMB->ParameterCount;
5833 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5834 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5835 else
5836 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5837 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005838 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005839 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840 pSMB->ByteCount = cpu_to_le16(byte_count);
5841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5842 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005843 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005844 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845
5846 cifs_buf_release(pSMB);
5847
5848 if (rc == -EAGAIN)
5849 goto SetTimesRetry;
5850
5851 return rc;
5852}
5853
5854/* Can not be used to set time stamps yet (due to old DOS time format) */
5855/* Can be used to set attributes */
5856#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5857 handling it anyway and NT4 was what we thought it would be needed for
5858 Do not delete it until we prove whether needed for Win9x though */
5859int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005860CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 __u16 dos_attrs, const struct nls_table *nls_codepage)
5862{
5863 SETATTR_REQ *pSMB = NULL;
5864 SETATTR_RSP *pSMBr = NULL;
5865 int rc = 0;
5866 int bytes_returned;
5867 int name_len;
5868
Joe Perchesf96637b2013-05-04 22:12:25 -05005869 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870
5871SetAttrLgcyRetry:
5872 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5873 (void **) &pSMBr);
5874 if (rc)
5875 return rc;
5876
5877 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5878 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005879 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5880 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 name_len++; /* trailing null */
5882 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005883 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 name_len = strnlen(fileName, PATH_MAX);
5885 name_len++; /* trailing null */
5886 strncpy(pSMB->fileName, fileName, name_len);
5887 }
5888 pSMB->attr = cpu_to_le16(dos_attrs);
5889 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005890 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005894 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005895 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896
5897 cifs_buf_release(pSMB);
5898
5899 if (rc == -EAGAIN)
5900 goto SetAttrLgcyRetry;
5901
5902 return rc;
5903}
5904#endif /* temporarily unneeded SetAttr legacy function */
5905
Jeff Layton654cf142009-07-09 20:02:49 -04005906static void
5907cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5908 const struct cifs_unix_set_info_args *args)
5909{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005910 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005911 u64 mode = args->mode;
5912
Eric W. Biederman49418b22013-02-06 00:57:56 -08005913 if (uid_valid(args->uid))
5914 uid = from_kuid(&init_user_ns, args->uid);
5915 if (gid_valid(args->gid))
5916 gid = from_kgid(&init_user_ns, args->gid);
5917
Jeff Layton654cf142009-07-09 20:02:49 -04005918 /*
5919 * Samba server ignores set of file size to zero due to bugs in some
5920 * older clients, but we should be precise - we use SetFileSize to
5921 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005922 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005923 * zero instead of -1 here
5924 */
5925 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5926 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5927 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5928 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5929 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005930 data_offset->Uid = cpu_to_le64(uid);
5931 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005932 /* better to leave device as zero when it is */
5933 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5934 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5935 data_offset->Permissions = cpu_to_le64(mode);
5936
5937 if (S_ISREG(mode))
5938 data_offset->Type = cpu_to_le32(UNIX_FILE);
5939 else if (S_ISDIR(mode))
5940 data_offset->Type = cpu_to_le32(UNIX_DIR);
5941 else if (S_ISLNK(mode))
5942 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5943 else if (S_ISCHR(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5945 else if (S_ISBLK(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5947 else if (S_ISFIFO(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5949 else if (S_ISSOCK(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5951}
5952
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005954CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005955 const struct cifs_unix_set_info_args *args,
5956 u16 fid, u32 pid_of_opener)
5957{
5958 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005959 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005960 int rc = 0;
5961 u16 params, param_offset, offset, byte_count, count;
5962
Joe Perchesf96637b2013-05-04 22:12:25 -05005963 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005964 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5965
5966 if (rc)
5967 return rc;
5968
5969 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5970 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5971
5972 params = 6;
5973 pSMB->MaxSetupCount = 0;
5974 pSMB->Reserved = 0;
5975 pSMB->Flags = 0;
5976 pSMB->Timeout = 0;
5977 pSMB->Reserved2 = 0;
5978 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5979 offset = param_offset + params;
5980
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005981 data_offset = (char *)pSMB +
5982 offsetof(struct smb_hdr, Protocol) + offset;
5983
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005984 count = sizeof(FILE_UNIX_BASIC_INFO);
5985
5986 pSMB->MaxParameterCount = cpu_to_le16(2);
5987 /* BB find max SMB PDU from sess */
5988 pSMB->MaxDataCount = cpu_to_le16(1000);
5989 pSMB->SetupCount = 1;
5990 pSMB->Reserved3 = 0;
5991 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5992 byte_count = 3 /* pad */ + params + count;
5993 pSMB->DataCount = cpu_to_le16(count);
5994 pSMB->ParameterCount = cpu_to_le16(params);
5995 pSMB->TotalDataCount = pSMB->DataCount;
5996 pSMB->TotalParameterCount = pSMB->ParameterCount;
5997 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5998 pSMB->DataOffset = cpu_to_le16(offset);
5999 pSMB->Fid = fid;
6000 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6001 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006002 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006003 pSMB->ByteCount = cpu_to_le16(byte_count);
6004
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006005 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006006
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006007 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006008 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006009 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006010 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6011 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006012
6013 /* Note: On -EAGAIN error only caller can retry on handle based calls
6014 since file handle passed in no longer valid */
6015
6016 return rc;
6017}
6018
6019int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006020CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006021 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006022 const struct cifs_unix_set_info_args *args,
6023 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024{
6025 TRANSACTION2_SPI_REQ *pSMB = NULL;
6026 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6027 int name_len;
6028 int rc = 0;
6029 int bytes_returned = 0;
6030 FILE_UNIX_BASIC_INFO *data_offset;
6031 __u16 params, param_offset, offset, count, byte_count;
6032
Joe Perchesf96637b2013-05-04 22:12:25 -05006033 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034setPermsRetry:
6035 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6036 (void **) &pSMBr);
6037 if (rc)
6038 return rc;
6039
6040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6041 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006042 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006043 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 name_len++; /* trailing null */
6045 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006046 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006047 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006049 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 }
6051
6052 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006053 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006055 /* BB find max SMB PDU from sess structure BB */
6056 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057 pSMB->MaxSetupCount = 0;
6058 pSMB->Reserved = 0;
6059 pSMB->Flags = 0;
6060 pSMB->Timeout = 0;
6061 pSMB->Reserved2 = 0;
6062 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006063 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 offset = param_offset + params;
6065 data_offset =
6066 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6067 offset);
6068 memset(data_offset, 0, count);
6069 pSMB->DataOffset = cpu_to_le16(offset);
6070 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6071 pSMB->SetupCount = 1;
6072 pSMB->Reserved3 = 0;
6073 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6074 byte_count = 3 /* pad */ + params + count;
6075 pSMB->ParameterCount = cpu_to_le16(params);
6076 pSMB->DataCount = cpu_to_le16(count);
6077 pSMB->TotalParameterCount = pSMB->ParameterCount;
6078 pSMB->TotalDataCount = pSMB->DataCount;
6079 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6080 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006081 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006082
Jeff Layton654cf142009-07-09 20:02:49 -04006083 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084
6085 pSMB->ByteCount = cpu_to_le16(byte_count);
6086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006088 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006089 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090
Steve French0d817bc2008-05-22 02:02:03 +00006091 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 if (rc == -EAGAIN)
6093 goto setPermsRetry;
6094 return rc;
6095}
6096
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006098/*
6099 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6100 * function used by listxattr and getxattr type calls. When ea_name is set,
6101 * it looks for that attribute name and stuffs that value into the EAData
6102 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6103 * buffer. In both cases, the return value is either the length of the
6104 * resulting data or a negative error code. If EAData is a NULL pointer then
6105 * the data isn't copied to it, but the length is returned.
6106 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006108CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006109 const unsigned char *searchName, const unsigned char *ea_name,
6110 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006111 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112{
6113 /* BB assumes one setup word */
6114 TRANSACTION2_QPI_REQ *pSMB = NULL;
6115 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006116 int remap = cifs_remap(cifs_sb);
6117 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 int rc = 0;
6119 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006120 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006121 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006122 struct fea *temp_fea;
6123 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006124 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006125 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006126 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127
Joe Perchesf96637b2013-05-04 22:12:25 -05006128 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129QAllEAsRetry:
6130 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6131 (void **) &pSMBr);
6132 if (rc)
6133 return rc;
6134
6135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006136 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006137 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6138 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006139 list_len++; /* trailing null */
6140 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006142 list_len = strnlen(searchName, PATH_MAX);
6143 list_len++; /* trailing null */
6144 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145 }
6146
Jeff Layton6e462b92010-02-10 16:18:26 -05006147 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 pSMB->TotalDataCount = 0;
6149 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006150 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006151 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 pSMB->MaxSetupCount = 0;
6153 pSMB->Reserved = 0;
6154 pSMB->Flags = 0;
6155 pSMB->Timeout = 0;
6156 pSMB->Reserved2 = 0;
6157 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006158 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 pSMB->DataCount = 0;
6160 pSMB->DataOffset = 0;
6161 pSMB->SetupCount = 1;
6162 pSMB->Reserved3 = 0;
6163 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6164 byte_count = params + 1 /* pad */ ;
6165 pSMB->TotalParameterCount = cpu_to_le16(params);
6166 pSMB->ParameterCount = pSMB->TotalParameterCount;
6167 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6168 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006169 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170 pSMB->ByteCount = cpu_to_le16(byte_count);
6171
6172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6174 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006175 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006176 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178
6179
6180 /* BB also check enough total bytes returned */
6181 /* BB we need to improve the validity checking
6182 of these trans2 responses */
6183
6184 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006185 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006186 rc = -EIO; /* bad smb */
6187 goto QAllEAsOut;
6188 }
6189
6190 /* check that length of list is not more than bcc */
6191 /* check that each entry does not go beyond length
6192 of list */
6193 /* check that each element of each entry does not
6194 go beyond end of list */
6195 /* validate_trans2_offsets() */
6196 /* BB check if start of smb + data_offset > &bcc+ bcc */
6197
6198 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6199 ea_response_data = (struct fealist *)
6200 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6201
Jeff Layton6e462b92010-02-10 16:18:26 -05006202 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006203 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006204 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006205 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006206 /* didn't find the named attribute */
6207 if (ea_name)
6208 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006209 goto QAllEAsOut;
6210 }
6211
Jeff Layton0cd126b2010-02-10 16:18:26 -05006212 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006213 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006214 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006215 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006216 rc = -EIO;
6217 goto QAllEAsOut;
6218 }
6219
Jeff Laytonf0d38682010-02-10 16:18:26 -05006220 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006221 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006222 temp_fea = ea_response_data->list;
6223 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006224 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006225 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006226 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006227
Jeff Layton6e462b92010-02-10 16:18:26 -05006228 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006229 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006230 /* make sure we can read name_len and value_len */
6231 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006232 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006233 rc = -EIO;
6234 goto QAllEAsOut;
6235 }
6236
6237 name_len = temp_fea->name_len;
6238 value_len = le16_to_cpu(temp_fea->value_len);
6239 list_len -= name_len + 1 + value_len;
6240 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006241 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006242 rc = -EIO;
6243 goto QAllEAsOut;
6244 }
6245
Jeff Layton31c05192010-02-10 16:18:26 -05006246 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006247 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006248 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006249 temp_ptr += name_len + 1;
6250 rc = value_len;
6251 if (buf_size == 0)
6252 goto QAllEAsOut;
6253 if ((size_t)value_len > buf_size) {
6254 rc = -ERANGE;
6255 goto QAllEAsOut;
6256 }
6257 memcpy(EAData, temp_ptr, value_len);
6258 goto QAllEAsOut;
6259 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006260 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006261 /* account for prefix user. and trailing null */
6262 rc += (5 + 1 + name_len);
6263 if (rc < (int) buf_size) {
6264 memcpy(EAData, "user.", 5);
6265 EAData += 5;
6266 memcpy(EAData, temp_ptr, name_len);
6267 EAData += name_len;
6268 /* null terminate name */
6269 *EAData = 0;
6270 ++EAData;
6271 } else if (buf_size == 0) {
6272 /* skip copy - calc size only */
6273 } else {
6274 /* stop before overrun buffer */
6275 rc = -ERANGE;
6276 break;
6277 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006278 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006279 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006280 temp_fea = (struct fea *)temp_ptr;
6281 }
6282
Jeff Layton31c05192010-02-10 16:18:26 -05006283 /* didn't find the named attribute */
6284 if (ea_name)
6285 rc = -ENODATA;
6286
Jeff Laytonf0d38682010-02-10 16:18:26 -05006287QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006288 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 if (rc == -EAGAIN)
6290 goto QAllEAsRetry;
6291
6292 return (ssize_t)rc;
6293}
6294
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006296CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6297 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006298 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006299 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300{
6301 struct smb_com_transaction2_spi_req *pSMB = NULL;
6302 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6303 struct fealist *parm_data;
6304 int name_len;
6305 int rc = 0;
6306 int bytes_returned = 0;
6307 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006308 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309
Joe Perchesf96637b2013-05-04 22:12:25 -05006310 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311SetEARetry:
6312 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6313 (void **) &pSMBr);
6314 if (rc)
6315 return rc;
6316
6317 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6318 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006319 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6320 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 name_len++; /* trailing null */
6322 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006323 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 name_len = strnlen(fileName, PATH_MAX);
6325 name_len++; /* trailing null */
6326 strncpy(pSMB->FileName, fileName, name_len);
6327 }
6328
6329 params = 6 + name_len;
6330
6331 /* done calculating parms using name_len of file name,
6332 now use name_len to calculate length of ea name
6333 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006334 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 name_len = 0;
6336 else
Steve French50c2f752007-07-13 00:33:32 +00006337 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006339 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006341 /* BB find max SMB PDU from sess */
6342 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343 pSMB->MaxSetupCount = 0;
6344 pSMB->Reserved = 0;
6345 pSMB->Flags = 0;
6346 pSMB->Timeout = 0;
6347 pSMB->Reserved2 = 0;
6348 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006349 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 offset = param_offset + params;
6351 pSMB->InformationLevel =
6352 cpu_to_le16(SMB_SET_FILE_EA);
6353
Arnd Bergmannade7db92018-02-02 16:48:47 +01006354 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6356 pSMB->DataOffset = cpu_to_le16(offset);
6357 pSMB->SetupCount = 1;
6358 pSMB->Reserved3 = 0;
6359 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6360 byte_count = 3 /* pad */ + params + count;
6361 pSMB->DataCount = cpu_to_le16(count);
6362 parm_data->list_len = cpu_to_le32(count);
6363 parm_data->list[0].EA_flags = 0;
6364 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006365 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006367 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006368 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 parm_data->list[0].name[name_len] = 0;
6370 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6371 /* caller ensures that ea_value_len is less than 64K but
6372 we need to ensure that it fits within the smb */
6373
Steve French50c2f752007-07-13 00:33:32 +00006374 /*BB add length check to see if it would fit in
6375 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006376 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6377 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006378 memcpy(parm_data->list[0].name+name_len+1,
6379 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380
6381 pSMB->TotalDataCount = pSMB->DataCount;
6382 pSMB->ParameterCount = cpu_to_le16(params);
6383 pSMB->TotalParameterCount = pSMB->ParameterCount;
6384 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006385 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 pSMB->ByteCount = cpu_to_le16(byte_count);
6387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006389 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006390 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
6392 cifs_buf_release(pSMB);
6393
6394 if (rc == -EAGAIN)
6395 goto SetEARetry;
6396
6397 return rc;
6398}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399#endif
Steve French0eff0e22011-02-24 05:39:23 +00006400
6401#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6402/*
6403 * Years ago the kernel added a "dnotify" function for Samba server,
6404 * to allow network clients (such as Windows) to display updated
6405 * lists of files in directory listings automatically when
6406 * files are added by one user when another user has the
6407 * same directory open on their desktop. The Linux cifs kernel
6408 * client hooked into the kernel side of this interface for
6409 * the same reason, but ironically when the VFS moved from
6410 * "dnotify" to "inotify" it became harder to plug in Linux
6411 * network file system clients (the most obvious use case
6412 * for notify interfaces is when multiple users can update
6413 * the contents of the same directory - exactly what network
6414 * file systems can do) although the server (Samba) could
6415 * still use it. For the short term we leave the worker
6416 * function ifdeffed out (below) until inotify is fixed
6417 * in the VFS to make it easier to plug in network file
6418 * system clients. If inotify turns out to be permanently
6419 * incompatible for network fs clients, we could instead simply
6420 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6421 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006422int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006423 const int notify_subdirs, const __u16 netfid,
6424 __u32 filter, struct file *pfile, int multishot,
6425 const struct nls_table *nls_codepage)
6426{
6427 int rc = 0;
6428 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6429 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6430 struct dir_notify_req *dnotify_req;
6431 int bytes_returned;
6432
Joe Perchesf96637b2013-05-04 22:12:25 -05006433 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006434 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6435 (void **) &pSMBr);
6436 if (rc)
6437 return rc;
6438
6439 pSMB->TotalParameterCount = 0 ;
6440 pSMB->TotalDataCount = 0;
6441 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006442 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006443 pSMB->MaxSetupCount = 4;
6444 pSMB->Reserved = 0;
6445 pSMB->ParameterOffset = 0;
6446 pSMB->DataCount = 0;
6447 pSMB->DataOffset = 0;
6448 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6449 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6450 pSMB->ParameterCount = pSMB->TotalParameterCount;
6451 if (notify_subdirs)
6452 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6453 pSMB->Reserved2 = 0;
6454 pSMB->CompletionFilter = cpu_to_le32(filter);
6455 pSMB->Fid = netfid; /* file handle always le */
6456 pSMB->ByteCount = 0;
6457
6458 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6459 (struct smb_hdr *)pSMBr, &bytes_returned,
6460 CIFS_ASYNC_OP);
6461 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006462 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006463 } else {
6464 /* Add file to outstanding requests */
6465 /* BB change to kmem cache alloc */
6466 dnotify_req = kmalloc(
6467 sizeof(struct dir_notify_req),
6468 GFP_KERNEL);
6469 if (dnotify_req) {
6470 dnotify_req->Pid = pSMB->hdr.Pid;
6471 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6472 dnotify_req->Mid = pSMB->hdr.Mid;
6473 dnotify_req->Tid = pSMB->hdr.Tid;
6474 dnotify_req->Uid = pSMB->hdr.Uid;
6475 dnotify_req->netfid = netfid;
6476 dnotify_req->pfile = pfile;
6477 dnotify_req->filter = filter;
6478 dnotify_req->multishot = multishot;
6479 spin_lock(&GlobalMid_Lock);
6480 list_add_tail(&dnotify_req->lhead,
6481 &GlobalDnotifyReqList);
6482 spin_unlock(&GlobalMid_Lock);
6483 } else
6484 rc = -ENOMEM;
6485 }
6486 cifs_buf_release(pSMB);
6487 return rc;
6488}
6489#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */