blob: 0496934feecb777b6a7ae53a00003278f23517ea [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"
Pavel Shilovskyd9191312019-12-10 11:44:52 -080045#include "smb2proto.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040046#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070047#include "smbdirect.h"
Paulo Alcantara08744012018-11-14 17:24:29 -020048#ifdef CONFIG_CIFS_DFS_UPCALL
49#include "dfs_cache.h"
50#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#ifdef CONFIG_CIFS_POSIX
53static struct {
54 int index;
55 char *name;
56} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000057#ifdef CONFIG_CIFS_WEAK_PW_HASH
58 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000059 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000060#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000061 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000062 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 {BAD_PROT, "\2"}
64};
65#else
66static struct {
67 int index;
68 char *name;
69} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000070#ifdef CONFIG_CIFS_WEAK_PW_HASH
71 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000072 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000073#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000074 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 {BAD_PROT, "\2"}
76};
77#endif
78
Steve French39798772006-05-31 22:40:51 +000079/* define the number of elements in the cifs dialect array */
80#ifdef CONFIG_CIFS_POSIX
81#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000082#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000083#else
84#define CIFS_NUM_PROT 2
85#endif /* CIFS_WEAK_PW_HASH */
86#else /* not posix */
87#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000088#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000089#else
90#define CIFS_NUM_PROT 1
91#endif /* CONFIG_CIFS_WEAK_PW_HASH */
92#endif /* CIFS_POSIX */
93
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040094/*
95 * Mark as invalid, all open files on tree connections since they
96 * were closed when session to server was lost.
97 */
98void
99cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100{
101 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000102 struct list_head *tmp;
103 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400105 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500106 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400107 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000108 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000109 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400110 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 }
Steve French3afca262016-09-22 18:58:16 -0500112 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -0500113
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000114 mutex_lock(&tcon->crfid.fid_mutex);
115 tcon->crfid.is_valid = false;
Pavel Shilovskyd9191312019-12-10 11:44:52 -0800116 /* cached handle is not valid, so SMB2_CLOSE won't be sent below */
117 close_shroot_lease_locked(&tcon->crfid);
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000118 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
119 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -0500120
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400121 /*
122 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
123 * to this tcon.
124 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Jeff Layton9162ab22009-09-03 12:07:17 -0400127/* reconnect the socket, tcon, and smb session if needed */
128static int
Steve French96daf2b2011-05-27 04:34:02 +0000129cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400130{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400131 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000132 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400133 struct TCP_Server_Info *server;
134 struct nls_table *nls_codepage;
Paulo Alcantara08744012018-11-14 17:24:29 -0200135 int retries;
Jeff Layton9162ab22009-09-03 12:07:17 -0400136
137 /*
138 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
139 * tcp and smb session status done differently for those three - in the
140 * calling routine
141 */
142 if (!tcon)
143 return 0;
144
145 ses = tcon->ses;
146 server = ses->server;
147
148 /*
149 * only tree disconnect, open, and write, (and ulogoff which does not
150 * have tcon) are allowed as we start force umount
151 */
152 if (tcon->tidStatus == CifsExiting) {
153 if (smb_command != SMB_COM_WRITE_ANDX &&
154 smb_command != SMB_COM_OPEN_ANDX &&
155 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500156 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
157 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400158 return -ENODEV;
159 }
160 }
161
Paulo Alcantara08744012018-11-14 17:24:29 -0200162 retries = server->nr_targets;
163
Jeff Layton9162ab22009-09-03 12:07:17 -0400164 /*
Paulo Alcantara08744012018-11-14 17:24:29 -0200165 * Give demultiplex thread up to 10 seconds to each target available for
166 * reconnect -- should be greater than cifs socket timeout which is 7
167 * seconds.
Jeff Layton9162ab22009-09-03 12:07:17 -0400168 */
169 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300170 rc = wait_event_interruptible_timeout(server->response_q,
171 (server->tcpStatus != CifsNeedReconnect),
172 10 * HZ);
173 if (rc < 0) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700174 cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
175 __func__);
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300176 return -ERESTARTSYS;
177 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400178
Steve Frenchfd88ce92011-04-12 01:01:14 +0000179 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400180 if (server->tcpStatus != CifsNeedReconnect)
181 break;
182
Ronnie Sahlberg09c40b12020-02-06 13:55:19 +1000183 if (retries && --retries)
Paulo Alcantara08744012018-11-14 17:24:29 -0200184 continue;
185
Jeff Layton9162ab22009-09-03 12:07:17 -0400186 /*
187 * on "soft" mounts we wait once. Hard mounts keep
188 * retrying until process is killed or server comes
189 * back on-line
190 */
Jeff Laytond4025392011-02-07 08:54:35 -0500191 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500192 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400193 return -EHOSTDOWN;
194 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200195 retries = server->nr_targets;
Jeff Layton9162ab22009-09-03 12:07:17 -0400196 }
197
198 if (!ses->need_reconnect && !tcon->need_reconnect)
199 return 0;
200
201 nls_codepage = load_nls_default();
202
203 /*
204 * need to prevent multiple threads trying to simultaneously
205 * reconnect the same SMB session
206 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000207 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200208
209 /*
210 * Recheck after acquire mutex. If another thread is negotiating
211 * and the server never sends an answer the socket will be closed
212 * and tcpStatus set to reconnect.
213 */
214 if (server->tcpStatus == CifsNeedReconnect) {
215 rc = -EHOSTDOWN;
216 mutex_unlock(&ses->session_mutex);
217 goto out;
218 }
219
Jeff Layton198b5682010-04-24 07:57:48 -0400220 rc = cifs_negotiate_protocol(0, ses);
221 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400222 rc = cifs_setup_session(0, ses, nls_codepage);
223
224 /* do we need to reconnect tcon? */
225 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000226 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400227 goto out;
228 }
229
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400230 cifs_mark_open_files_invalid(tcon);
Stefan Metzmacher565674d2020-07-21 09:36:38 -0300231 rc = cifs_tree_connect(0, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000232 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500233 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400234
Steve Frenchc318e6c2018-04-04 14:08:52 -0500235 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700236 pr_warn_once("reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400237 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500238 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400239
Jeff Layton9162ab22009-09-03 12:07:17 -0400240 atomic_inc(&tconInfoReconnectCount);
241
242 /* tell server Unix caps we support */
Stefan Metzmacher864138c2020-02-24 14:15:00 +0100243 if (cap_unix(ses))
Jeff Layton9162ab22009-09-03 12:07:17 -0400244 reset_cifs_unix_caps(0, tcon, NULL, NULL);
245
246 /*
247 * Removed call to reopen open files here. It is safer (and faster) to
248 * reopen files one at a time as needed in read and write.
249 *
250 * FIXME: what about file locks? don't we need to reclaim them ASAP?
251 */
252
253out:
254 /*
255 * Check if handle based operation so we know whether we can continue
256 * or not without returning to caller to reset file handle
257 */
258 switch (smb_command) {
259 case SMB_COM_READ_ANDX:
260 case SMB_COM_WRITE_ANDX:
261 case SMB_COM_CLOSE:
262 case SMB_COM_FIND_CLOSE2:
263 case SMB_COM_LOCKING_ANDX:
264 rc = -EAGAIN;
265 }
266
267 unload_nls(nls_codepage);
268 return rc;
269}
270
Steve Frenchad7a2922008-02-07 23:25:02 +0000271/* Allocate and return pointer to an SMB request buffer, and set basic
272 SMB information in the SMB header. If the return code is zero, this
273 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274static int
Steve French96daf2b2011-05-27 04:34:02 +0000275small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000276 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
Jeff Laytonf5695992010-09-29 15:27:08 -0400278 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Jeff Layton9162ab22009-09-03 12:07:17 -0400280 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000281 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return rc;
283
284 *request_buf = cifs_small_buf_get();
285 if (*request_buf == NULL) {
286 /* BB should we add a retry in here if not a writepage? */
287 return -ENOMEM;
288 }
289
Steve French63135e02007-07-17 17:34:02 +0000290 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000291 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Steve French790fe572007-07-07 19:25:05 +0000293 if (tcon != NULL)
294 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700295
Jeff Laytonf5695992010-09-29 15:27:08 -0400296 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000297}
298
Steve French12b3b8f2006-02-09 21:12:47 +0000299int
Steve French50c2f752007-07-13 00:33:32 +0000300small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000301 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000302{
303 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000304 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000305
Steve French5815449d2006-02-14 01:36:20 +0000306 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000307 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000308 return rc;
309
Steve French04fdabe2006-02-10 05:52:50 +0000310 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400311 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000312 if (ses->capabilities & CAP_UNICODE)
313 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000314 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000315 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
316
317 /* uid, tid can stay at zero as set in header assemble */
318
Steve French50c2f752007-07-13 00:33:32 +0000319 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000320 this function is used after 1st of session setup requests */
321
322 return rc;
323}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325/* If the return code is zero, this function must fill in request_buf pointer */
326static int
Steve French96daf2b2011-05-27 04:34:02 +0000327__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400328 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 *request_buf = cifs_buf_get();
331 if (*request_buf == NULL) {
332 /* BB should we add a retry in here if not a writepage? */
333 return -ENOMEM;
334 }
335 /* Although the original thought was we needed the response buf for */
336 /* potential retries of smb operations it turns out we can determine */
337 /* from the mid flags when the request buffer can be resent without */
338 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000339 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000340 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000343 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Steve French790fe572007-07-07 19:25:05 +0000345 if (tcon != NULL)
346 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700347
Jeff Laytonf5695992010-09-29 15:27:08 -0400348 return 0;
349}
350
351/* If the return code is zero, this function must fill in request_buf pointer */
352static int
Steve French96daf2b2011-05-27 04:34:02 +0000353smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400354 void **request_buf, void **response_buf)
355{
356 int rc;
357
358 rc = cifs_reconnect_tcon(tcon, smb_command);
359 if (rc)
360 return rc;
361
362 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
363}
364
365static int
Steve French96daf2b2011-05-27 04:34:02 +0000366smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400367 void **request_buf, void **response_buf)
368{
369 if (tcon->ses->need_reconnect || tcon->need_reconnect)
370 return -EHOSTDOWN;
371
372 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
Steve French50c2f752007-07-13 00:33:32 +0000375static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
Jeff Layton12df83c2011-01-20 13:36:51 -0500377 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Jeff Layton12df83c2011-01-20 13:36:51 -0500379 /* check for plausible wct */
380 if (pSMB->hdr.WordCount < 10)
381 goto vt2_err;
382
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500384 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
385 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
386 goto vt2_err;
387
Jeff Layton12df83c2011-01-20 13:36:51 -0500388 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
389 if (total_size >= 512)
390 goto vt2_err;
391
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400392 /* check that bcc is at least as big as parms + data, and that it is
393 * less than negotiated smb buffer
394 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500395 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
396 if (total_size > get_bcc(&pSMB->hdr) ||
397 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
398 goto vt2_err;
399
400 return 0;
401vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000402 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500404 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405}
Jeff Layton690c5222011-01-20 13:36:51 -0500406
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400407static int
Jeff Layton3f618222013-06-12 19:52:14 -0500408decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400409{
410 int rc = 0;
411 u16 count;
412 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500413 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400414
415 count = get_bcc(&pSMBr->hdr);
416 if (count < SMB1_CLIENT_GUID_SIZE)
417 return -EIO;
418
419 spin_lock(&cifs_tcp_ses_lock);
420 if (server->srv_count > 1) {
421 spin_unlock(&cifs_tcp_ses_lock);
422 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
423 cifs_dbg(FYI, "server UID changed\n");
424 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
425 }
426 } else {
427 spin_unlock(&cifs_tcp_ses_lock);
428 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
429 }
430
431 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500432 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400433 } else {
434 count -= SMB1_CLIENT_GUID_SIZE;
435 rc = decode_negTokenInit(
436 pSMBr->u.extended_response.SecurityBlob, count, server);
437 if (rc != 1)
438 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400439 }
440
441 return 0;
442}
443
Jeff Layton9ddec562013-05-26 07:00:58 -0400444int
Jeff Layton38d77c52013-05-26 07:01:00 -0400445cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400446{
Jeff Layton502858822013-06-27 12:45:00 -0400447 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
448 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400449 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
450
451 /*
452 * Is signing required by mnt options? If not then check
453 * global_secflags to see if it is there.
454 */
455 if (!mnt_sign_required)
456 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
457 CIFSSEC_MUST_SIGN);
458
459 /*
460 * If signing is required then it's automatically enabled too,
461 * otherwise, check to see if the secflags allow it.
462 */
463 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
464 (global_secflags & CIFSSEC_MAY_SIGN);
465
466 /* If server requires signing, does client allow it? */
467 if (srv_sign_required) {
468 if (!mnt_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700469 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400470 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400471 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400472 server->sign = true;
473 }
474
475 /* If client requires signing, does server allow it? */
476 if (mnt_sign_required) {
477 if (!srv_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700478 cifs_dbg(VFS, "Server does not support signing!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400479 return -ENOTSUPP;
480 }
481 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400482 }
483
Long Libb4c0412018-04-17 12:17:08 -0700484 if (cifs_rdma_enabled(server) && server->sign)
Joe Perchesa0a30362020-04-14 22:42:53 -0700485 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");
Long Libb4c0412018-04-17 12:17:08 -0700486
Jeff Layton9ddec562013-05-26 07:00:58 -0400487 return 0;
488}
489
Jeff Layton2190eca2013-05-26 07:00:57 -0400490#ifdef CONFIG_CIFS_WEAK_PW_HASH
491static int
Jeff Layton3f618222013-06-12 19:52:14 -0500492decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400493{
494 __s16 tmp;
495 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
496
497 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
498 return -EOPNOTSUPP;
499
Jeff Layton2190eca2013-05-26 07:00:57 -0400500 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
501 server->maxReq = min_t(unsigned int,
502 le16_to_cpu(rsp->MaxMpxCount),
503 cifs_max_pending);
504 set_credits(server, server->maxReq);
505 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800506 /* set up max_read for readpages check */
507 server->max_read = server->maxBuf;
Jeff Layton2190eca2013-05-26 07:00:57 -0400508 /* even though we do not use raw we might as well set this
509 accurately, in case we ever find a need for it */
510 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
511 server->max_rw = 0xFF00;
512 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
513 } else {
514 server->max_rw = 0;/* do not need to use raw anyway */
515 server->capabilities = CAP_MPX_MODE;
516 }
517 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
518 if (tmp == -1) {
519 /* OS/2 often does not set timezone therefore
520 * we must use server time to calc time zone.
521 * Could deviate slightly from the right zone.
522 * Smallest defined timezone difference is 15 minutes
523 * (i.e. Nepal). Rounding up/down is done to match
524 * this requirement.
525 */
526 int val, seconds, remain, result;
Arnd Bergmann95390202018-06-19 17:27:58 +0200527 struct timespec64 ts;
528 time64_t utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400529 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
530 rsp->SrvTime.Time, 0);
Arnd Bergmann95390202018-06-19 17:27:58 +0200531 cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
532 ts.tv_sec, utc,
533 utc - ts.tv_sec);
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700534 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400535 seconds = abs(val);
536 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
537 remain = seconds % MIN_TZ_ADJ;
538 if (remain >= (MIN_TZ_ADJ / 2))
539 result += MIN_TZ_ADJ;
540 if (val < 0)
541 result = -result;
542 server->timeAdj = result;
543 } else {
544 server->timeAdj = (int)tmp;
545 server->timeAdj *= 60; /* also in seconds */
546 }
547 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
548
549
550 /* BB get server time for time conversions and add
551 code to use it and timezone since this is not UTC */
552
553 if (rsp->EncryptionKeyLength ==
554 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
555 memcpy(server->cryptkey, rsp->EncryptionKey,
556 CIFS_CRYPTO_KEY_SIZE);
557 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
558 return -EIO; /* need cryptkey unless plain text */
559 }
560
561 cifs_dbg(FYI, "LANMAN negotiated\n");
562 return 0;
563}
564#else
565static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500566decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400567{
568 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
569 return -EOPNOTSUPP;
570}
571#endif
572
Jeff Layton91934002013-05-26 07:00:58 -0400573static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500574should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400575{
Jeff Layton3f618222013-06-12 19:52:14 -0500576 switch (sectype) {
577 case RawNTLMSSP:
578 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400579 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500580 case Unspecified:
581 if (global_secflags &
582 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
583 return true;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500584 fallthrough;
Jeff Layton3f618222013-06-12 19:52:14 -0500585 default:
586 return false;
587 }
Jeff Layton91934002013-05-26 07:00:58 -0400588}
589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400591CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
593 NEGOTIATE_REQ *pSMB;
594 NEGOTIATE_RSP *pSMBr;
595 int rc = 0;
596 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000597 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400598 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 u16 count;
600
Jeff Layton3534b852013-05-24 07:41:01 -0400601 if (!server) {
602 WARN(1, "%s: server is NULL!\n", __func__);
603 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 }
Jeff Layton3534b852013-05-24 07:41:01 -0400605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
607 (void **) &pSMB, (void **) &pSMBr);
608 if (rc)
609 return rc;
Steve French750d1152006-06-27 06:28:30 +0000610
Pavel Shilovsky88257362012-05-23 14:01:59 +0400611 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000612 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000613
Jeff Layton3f618222013-06-12 19:52:14 -0500614 if (should_set_ext_sec_flag(ses->sectype)) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700615 cifs_dbg(FYI, "Requesting extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000616 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
617 }
Steve French50c2f752007-07-13 00:33:32 +0000618
Steve French39798772006-05-31 22:40:51 +0000619 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000620 /*
621 * We know that all the name entries in the protocols array
622 * are short (< 16 bytes anyway) and are NUL terminated.
623 */
Steve French50c2f752007-07-13 00:33:32 +0000624 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000625 size_t len = strlen(protocols[i].name) + 1;
626
627 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
628 count += len;
Steve French39798772006-05-31 22:40:51 +0000629 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000630 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 pSMB->ByteCount = cpu_to_le16(count);
632
633 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
634 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000635 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000636 goto neg_err_exit;
637
Jeff Layton9bf67e52010-04-24 07:57:46 -0400638 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500639 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000640 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400641 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000642 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000643 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000644 could not negotiate a common dialect */
645 rc = -EOPNOTSUPP;
646 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000647 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400648 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500649 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400650 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000651 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000652 /* unknown wct */
653 rc = -EOPNOTSUPP;
654 goto neg_err_exit;
655 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400656 /* else wct == 17, NTLM or better */
657
Steve French96daf2b2011-05-27 04:34:02 +0000658 server->sec_mode = pSMBr->SecurityMode;
659 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500660 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000661
Steve French254e55e2006-06-04 05:53:15 +0000662 /* one byte, so no need to convert this or EncryptionKeyLen from
663 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300664 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
665 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400666 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000667 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400668 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800669 /* set up max_read for readpages check */
670 server->max_read = server->maxBuf;
Steve Frencheca6acf2009-02-20 05:43:09 +0000671 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500672 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000673 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000674 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
675 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400676
Jeff Laytone598d1d82013-05-26 07:00:59 -0400677 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
678 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500679 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000680 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100681 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
682 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400683 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500684 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400685 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000686 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400687 } else {
688 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000689 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400690 }
Steve French254e55e2006-06-04 05:53:15 +0000691
692signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400693 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400694 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000695neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700696 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000697
Joe Perchesf96637b2013-05-04 22:12:25 -0500698 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return rc;
700}
701
702int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400703CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
705 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Joe Perchesf96637b2013-05-04 22:12:25 -0500708 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500709
710 /* BB: do we need to check this? These should never be NULL. */
711 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
712 return -EIO;
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500715 * No need to return error on this operation if tid invalidated and
716 * closed on server already e.g. due to tcp session crashing. Also,
717 * the tcon is no longer on the list, so no need to take lock before
718 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 */
Steve French268875b2009-06-25 00:29:21 +0000720 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000721 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Steve French50c2f752007-07-13 00:33:32 +0000723 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700724 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500725 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return rc;
Steve French133672e2007-11-13 22:41:37 +0000727
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400728 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700729 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500731 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Steve French50c2f752007-07-13 00:33:32 +0000733 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500734 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 if (rc == -EAGAIN)
736 rc = 0;
737
738 return rc;
739}
740
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741/*
742 * This is a no-op for now. We're not really interested in the reply, but
743 * rather in the fact that the server sent one and that server->lstrp
744 * gets updated.
745 *
746 * FIXME: maybe we should consider checking that the reply matches request?
747 */
748static void
749cifs_echo_callback(struct mid_q_entry *mid)
750{
751 struct TCP_Server_Info *server = mid->callback_data;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800752 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500753
754 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800755 add_credits(server, &credits, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500756}
757
758int
759CIFSSMBEcho(struct TCP_Server_Info *server)
760{
761 ECHO_REQ *smb;
762 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800763 struct kvec iov[2];
764 struct smb_rqst rqst = { .rq_iov = iov,
765 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500766
Joe Perchesf96637b2013-05-04 22:12:25 -0500767 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500768
769 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
770 if (rc)
771 return rc;
772
Steve French26c9cb62017-05-02 13:35:20 -0500773 if (server->capabilities & CAP_UNICODE)
774 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
775
Jeff Layton766fdbb2011-01-11 07:24:21 -0500776 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000777 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500778 smb->hdr.WordCount = 1;
779 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400780 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500781 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000782 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800783
784 iov[0].iov_len = 4;
785 iov[0].iov_base = smb;
786 iov[1].iov_len = get_rfc1002_length(smb);
787 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500788
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800789 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +1000790 server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500791 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500792 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500793
794 cifs_small_buf_release(smb);
795
796 return rc;
797}
798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400800CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 LOGOFF_ANDX_REQ *pSMB;
803 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Joe Perchesf96637b2013-05-04 22:12:25 -0500805 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500806
807 /*
808 * BB: do we need to check validity of ses and server? They should
809 * always be valid since we have an active reference. If not, that
810 * should probably be a BUG()
811 */
812 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 return -EIO;
814
Steve Frenchd7b619c2010-02-25 05:36:46 +0000815 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000816 if (ses->need_reconnect)
817 goto session_already_dead; /* no need to send SMBlogoff if uid
818 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
820 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000821 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 return rc;
823 }
824
Pavel Shilovsky88257362012-05-23 14:01:59 +0400825 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700826
Jeff Layton38d77c52013-05-26 07:01:00 -0400827 if (ses->server->sign)
828 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 pSMB->hdr.Uid = ses->Suid;
831
832 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400833 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700834 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000835session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000836 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000839 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 error */
841 if (rc == -EAGAIN)
842 rc = 0;
843 return rc;
844}
845
846int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400847CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
848 const char *fileName, __u16 type,
849 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000850{
851 TRANSACTION2_SPI_REQ *pSMB = NULL;
852 TRANSACTION2_SPI_RSP *pSMBr = NULL;
853 struct unlink_psx_rq *pRqD;
854 int name_len;
855 int rc = 0;
856 int bytes_returned = 0;
857 __u16 params, param_offset, offset, byte_count;
858
Joe Perchesf96637b2013-05-04 22:12:25 -0500859 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000860PsxDelete:
861 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
862 (void **) &pSMBr);
863 if (rc)
864 return rc;
865
866 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
867 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600868 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
869 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000870 name_len++; /* trailing null */
871 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000872 } else {
873 name_len = copy_path_name(pSMB->FileName, fileName);
Steve French2d785a52007-07-15 01:48:57 +0000874 }
875
876 params = 6 + name_len;
877 pSMB->MaxParameterCount = cpu_to_le16(2);
878 pSMB->MaxDataCount = 0; /* BB double check this with jra */
879 pSMB->MaxSetupCount = 0;
880 pSMB->Reserved = 0;
881 pSMB->Flags = 0;
882 pSMB->Timeout = 0;
883 pSMB->Reserved2 = 0;
884 param_offset = offsetof(struct smb_com_transaction2_spi_req,
885 InformationLevel) - 4;
886 offset = param_offset + params;
887
888 /* Setup pointer to Request Data (inode type) */
889 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
890 pRqD->type = cpu_to_le16(type);
891 pSMB->ParameterOffset = cpu_to_le16(param_offset);
892 pSMB->DataOffset = cpu_to_le16(offset);
893 pSMB->SetupCount = 1;
894 pSMB->Reserved3 = 0;
895 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
896 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
897
898 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
899 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
900 pSMB->ParameterCount = cpu_to_le16(params);
901 pSMB->TotalParameterCount = pSMB->ParameterCount;
902 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
903 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000904 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000905 pSMB->ByteCount = cpu_to_le16(byte_count);
906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000908 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500909 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000910 cifs_buf_release(pSMB);
911
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400912 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000913
914 if (rc == -EAGAIN)
915 goto PsxDelete;
916
917 return rc;
918}
919
920int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700921CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
922 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
924 DELETE_FILE_REQ *pSMB = NULL;
925 DELETE_FILE_RSP *pSMBr = NULL;
926 int rc = 0;
927 int bytes_returned;
928 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500929 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931DelFileRetry:
932 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
933 (void **) &pSMBr);
934 if (rc)
935 return rc;
936
937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700938 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
939 PATH_MAX, cifs_sb->local_nls,
940 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 name_len++; /* trailing null */
942 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000943 } else {
944 name_len = copy_path_name(pSMB->fileName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946 pSMB->SearchAttributes =
947 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
948 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000949 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 pSMB->ByteCount = cpu_to_le16(name_len + 1);
951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400953 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000954 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500955 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 cifs_buf_release(pSMB);
958 if (rc == -EAGAIN)
959 goto DelFileRetry;
960
961 return rc;
962}
963
964int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400965CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
966 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
968 DELETE_DIRECTORY_REQ *pSMB = NULL;
969 DELETE_DIRECTORY_RSP *pSMBr = NULL;
970 int rc = 0;
971 int bytes_returned;
972 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500973 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Joe Perchesf96637b2013-05-04 22:12:25 -0500975 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976RmDirRetry:
977 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
978 (void **) &pSMBr);
979 if (rc)
980 return rc;
981
982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400983 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
984 PATH_MAX, cifs_sb->local_nls,
985 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len++; /* trailing null */
987 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000988 } else {
989 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 }
991
992 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000993 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 pSMB->ByteCount = cpu_to_le16(name_len + 1);
995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400997 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000998 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500999 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
1001 cifs_buf_release(pSMB);
1002 if (rc == -EAGAIN)
1003 goto RmDirRetry;
1004 return rc;
1005}
1006
1007int
Steve Frenchc3ca78e2019-09-25 00:32:13 -05001008CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
1009 struct cifs_tcon *tcon, const char *name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001010 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
1012 int rc = 0;
1013 CREATE_DIRECTORY_REQ *pSMB = NULL;
1014 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1015 int bytes_returned;
1016 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001017 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Joe Perchesf96637b2013-05-04 22:12:25 -05001019 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020MkDirRetry:
1021 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1022 (void **) &pSMBr);
1023 if (rc)
1024 return rc;
1025
1026 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001027 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001028 PATH_MAX, cifs_sb->local_nls,
1029 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 name_len++; /* trailing null */
1031 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001032 } else {
1033 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 }
1035
1036 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001037 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1039 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1040 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001041 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001042 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001043 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001044
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 cifs_buf_release(pSMB);
1046 if (rc == -EAGAIN)
1047 goto MkDirRetry;
1048 return rc;
1049}
1050
Steve French2dd29d32007-04-23 22:07:35 +00001051int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001052CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1053 __u32 posix_flags, __u64 mode, __u16 *netfid,
1054 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1055 const char *name, const struct nls_table *nls_codepage,
1056 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001057{
1058 TRANSACTION2_SPI_REQ *pSMB = NULL;
1059 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1060 int name_len;
1061 int rc = 0;
1062 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001063 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001064 OPEN_PSX_REQ *pdata;
1065 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001066
Joe Perchesf96637b2013-05-04 22:12:25 -05001067 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001068PsxCreat:
1069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1070 (void **) &pSMBr);
1071 if (rc)
1072 return rc;
1073
1074 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1075 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001076 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1077 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001078 name_len++; /* trailing null */
1079 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001080 } else {
1081 name_len = copy_path_name(pSMB->FileName, name);
Steve French2dd29d32007-04-23 22:07:35 +00001082 }
1083
1084 params = 6 + name_len;
1085 count = sizeof(OPEN_PSX_REQ);
1086 pSMB->MaxParameterCount = cpu_to_le16(2);
1087 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1088 pSMB->MaxSetupCount = 0;
1089 pSMB->Reserved = 0;
1090 pSMB->Flags = 0;
1091 pSMB->Timeout = 0;
1092 pSMB->Reserved2 = 0;
1093 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001094 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001095 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001096 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001097 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001098 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001099 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001100 pdata->OpenFlags = cpu_to_le32(*pOplock);
1101 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1102 pSMB->DataOffset = cpu_to_le16(offset);
1103 pSMB->SetupCount = 1;
1104 pSMB->Reserved3 = 0;
1105 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1106 byte_count = 3 /* pad */ + params + count;
1107
1108 pSMB->DataCount = cpu_to_le16(count);
1109 pSMB->ParameterCount = cpu_to_le16(params);
1110 pSMB->TotalDataCount = pSMB->DataCount;
1111 pSMB->TotalParameterCount = pSMB->ParameterCount;
1112 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1113 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001114 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001115 pSMB->ByteCount = cpu_to_le16(byte_count);
1116 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1117 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1118 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001119 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001120 goto psx_create_err;
1121 }
1122
Joe Perchesf96637b2013-05-04 22:12:25 -05001123 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001124 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1125
Jeff Layton820a8032011-05-04 08:05:26 -04001126 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001127 rc = -EIO; /* bad smb */
1128 goto psx_create_err;
1129 }
1130
1131 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001132 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001133 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001134
Steve French2dd29d32007-04-23 22:07:35 +00001135 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001136 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001137 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1138 /* Let caller know file was created so we can set the mode. */
1139 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001140 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001141 *pOplock |= CIFS_CREATE_ACTION;
1142 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001143 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1144 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001145 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001146 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001147 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001148 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001149 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001150 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001151 goto psx_create_err;
1152 }
Steve French50c2f752007-07-13 00:33:32 +00001153 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001154 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001155 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001156 }
Steve French2dd29d32007-04-23 22:07:35 +00001157
1158psx_create_err:
1159 cifs_buf_release(pSMB);
1160
Steve French65bc98b2009-07-10 15:27:25 +00001161 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001162 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001163 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001164 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001165
1166 if (rc == -EAGAIN)
1167 goto PsxCreat;
1168
Steve French50c2f752007-07-13 00:33:32 +00001169 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001170}
1171
Steve Frencha9d02ad2005-08-24 23:06:05 -07001172static __u16 convert_disposition(int disposition)
1173{
1174 __u16 ofun = 0;
1175
1176 switch (disposition) {
1177 case FILE_SUPERSEDE:
1178 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1179 break;
1180 case FILE_OPEN:
1181 ofun = SMBOPEN_OAPPEND;
1182 break;
1183 case FILE_CREATE:
1184 ofun = SMBOPEN_OCREATE;
1185 break;
1186 case FILE_OPEN_IF:
1187 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1188 break;
1189 case FILE_OVERWRITE:
1190 ofun = SMBOPEN_OTRUNC;
1191 break;
1192 case FILE_OVERWRITE_IF:
1193 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1194 break;
1195 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001196 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 ofun = SMBOPEN_OAPPEND; /* regular open */
1198 }
1199 return ofun;
1200}
1201
Jeff Layton35fc37d2008-05-14 10:22:03 -07001202static int
1203access_flags_to_smbopen_mode(const int access_flags)
1204{
1205 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1206
1207 if (masked_flags == GENERIC_READ)
1208 return SMBOPEN_READ;
1209 else if (masked_flags == GENERIC_WRITE)
1210 return SMBOPEN_WRITE;
1211
1212 /* just go for read/write */
1213 return SMBOPEN_READWRITE;
1214}
1215
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001217SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001218 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001219 const int access_flags, const int create_options, __u16 *netfid,
1220 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 const struct nls_table *nls_codepage, int remap)
1222{
1223 int rc = -EACCES;
1224 OPENX_REQ *pSMB = NULL;
1225 OPENX_RSP *pSMBr = NULL;
1226 int bytes_returned;
1227 int name_len;
1228 __u16 count;
1229
1230OldOpenRetry:
1231 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1232 (void **) &pSMBr);
1233 if (rc)
1234 return rc;
1235
1236 pSMB->AndXCommand = 0xFF; /* none */
1237
1238 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1239 count = 1; /* account for one byte pad to word boundary */
1240 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001241 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1242 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 name_len++; /* trailing null */
1244 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001245 } else {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 count = 0; /* no pad */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001247 name_len = copy_path_name(pSMB->fileName, fileName);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 }
1249 if (*pOplock & REQ_OPLOCK)
1250 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001251 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001253
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001255 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1257 /* set file as system file if special file such
1258 as fifo and server expecting SFU style and
1259 no Unix extensions */
1260
Steve French790fe572007-07-07 19:25:05 +00001261 if (create_options & CREATE_OPTION_SPECIAL)
1262 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001263 else /* BB FIXME BB */
1264 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265
Jeff Layton67750fb2008-05-09 22:28:02 +00001266 if (create_options & CREATE_OPTION_READONLY)
1267 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268
1269 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001270/* pSMB->CreateOptions = cpu_to_le32(create_options &
1271 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001272 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001273
1274 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001275 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001277 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278
1279 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001281 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001282 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001284 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001285 } else {
1286 /* BB verify if wct == 15 */
1287
Steve French582d21e2008-05-13 04:54:12 +00001288/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001289
1290 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1291 /* Let caller know file was created so we can set the mode. */
1292 /* Do we care about the CreateAction in any other cases? */
1293 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001294/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001295 *pOplock |= CIFS_CREATE_ACTION; */
1296 /* BB FIXME END */
1297
Steve French790fe572007-07-07 19:25:05 +00001298 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001299 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1300 pfile_info->LastAccessTime = 0; /* BB fixme */
1301 pfile_info->LastWriteTime = 0; /* BB fixme */
1302 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001303 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001304 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001305 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001306 pfile_info->AllocationSize =
1307 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1308 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001309 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001310 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001311 }
1312 }
1313
1314 cifs_buf_release(pSMB);
1315 if (rc == -EAGAIN)
1316 goto OldOpenRetry;
1317 return rc;
1318}
1319
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001321CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1322 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323{
Colin Ian King1afdea42019-07-23 16:09:19 +01001324 int rc;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001325 OPEN_REQ *req = NULL;
1326 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 int bytes_returned;
1328 int name_len;
1329 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001330 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1331 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001332 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001333 const struct nls_table *nls = cifs_sb->local_nls;
1334 int create_options = oparms->create_options;
1335 int desired_access = oparms->desired_access;
1336 int disposition = oparms->disposition;
1337 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001340 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1341 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (rc)
1343 return rc;
1344
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001345 /* no commands go after this */
1346 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001348 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1349 /* account for one byte pad to word boundary */
1350 count = 1;
1351 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1352 path, PATH_MAX, nls, remap);
1353 /* trailing null */
1354 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001356 req->NameLength = cpu_to_le16(name_len);
1357 } else {
1358 /* BB improve check for buffer overruns BB */
1359 /* no pad */
1360 count = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001361 name_len = copy_path_name(req->fileName, path);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001362 req->NameLength = cpu_to_le16(name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001364
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001365 if (*oplock & REQ_OPLOCK)
1366 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1367 else if (*oplock & REQ_BATCHOPLOCK)
1368 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1369
1370 req->DesiredAccess = cpu_to_le32(desired_access);
1371 req->AllocationSize = 0;
1372
1373 /*
1374 * Set file as system file if special file such as fifo and server
1375 * expecting SFU style and no Unix extensions.
1376 */
1377 if (create_options & CREATE_OPTION_SPECIAL)
1378 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1379 else
1380 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1381
1382 /*
1383 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1384 * sensitive checks for other servers such as Samba.
1385 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001387 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Jeff Layton67750fb2008-05-09 22:28:02 +00001389 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001390 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001391
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001392 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1393 req->CreateDisposition = cpu_to_le32(disposition);
1394 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1395
Steve French09d1db52005-04-28 22:41:08 -07001396 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001397 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1398 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
1400 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001401 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001403 req->ByteCount = cpu_to_le16(count);
1404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1405 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001406 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001408 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001409 cifs_buf_release(req);
1410 if (rc == -EAGAIN)
1411 goto openRetry;
1412 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001414
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001415 /* 1 byte no need to le_to_cpu */
1416 *oplock = rsp->OplockLevel;
1417 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001418 oparms->fid->netfid = rsp->Fid;
Aurelien Aptel86f740f2020-02-21 11:19:06 +01001419 oparms->fid->access = desired_access;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001420
1421 /* Let caller know file was created so we can set the mode. */
1422 /* Do we care about the CreateAction in any other cases? */
1423 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1424 *oplock |= CIFS_CREATE_ACTION;
1425
1426 if (buf) {
1427 /* copy from CreationTime to Attributes */
1428 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1429 /* the file_info buf is endian converted by caller */
1430 buf->AllocationSize = rsp->AllocationSize;
1431 buf->EndOfFile = rsp->EndOfFile;
1432 buf->NumberOfLinks = cpu_to_le32(1);
1433 buf->DeletePending = 0;
1434 }
1435
1436 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return rc;
1438}
1439
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440/*
1441 * Discard any remaining data in the current SMB. To do this, we borrow the
1442 * current bigbuf.
1443 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001444int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001445cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001447 unsigned int rfclen = server->pdu_size;
1448 int remaining = rfclen + server->vals->header_preamble_size -
1449 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450
1451 while (remaining > 0) {
1452 int length;
1453
1454 length = cifs_read_from_socket(server, server->bigbuf,
1455 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001456 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 if (length < 0)
1458 return length;
1459 server->total_read += length;
1460 remaining -= length;
1461 }
1462
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 return 0;
1464}
1465
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001466static int
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001467__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1468 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001469{
1470 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001471
Pavel Shilovsky350be252017-04-10 10:31:33 -07001472 length = cifs_discard_remaining_data(server);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001473 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001474 mid->resp_buf = server->smallbuf;
1475 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001476 return length;
1477}
1478
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001479static int
1480cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1481{
1482 struct cifs_readdata *rdata = mid->callback_data;
1483
1484 return __cifs_readv_discard(server, mid, rdata->result);
1485}
1486
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001487int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001488cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1489{
1490 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001491 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001492 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001493 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001494 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001495 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001496 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001497
Joe Perchesf96637b2013-05-04 22:12:25 -05001498 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1499 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001500
1501 /*
1502 * read the rest of READ_RSP header (sans Data array), or whatever we
1503 * can if there's not enough data. At this point, we've read down to
1504 * the Mid.
1505 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001506 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001507 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001508
Al Viroa6137302016-01-09 19:37:16 -05001509 length = cifs_read_from_socket(server,
1510 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001511 if (length < 0)
1512 return length;
1513 server->total_read += length;
1514
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001515 if (server->ops->is_session_expired &&
1516 server->ops->is_session_expired(buf)) {
1517 cifs_reconnect(server);
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001518 return -1;
1519 }
1520
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001521 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -08001522 server->ops->is_status_pending(buf, server)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001523 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001524 return -1;
1525 }
1526
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001527 /* set up first two iov for signature check and to get credits */
1528 rdata->iov[0].iov_base = buf;
Pavel Shilovskybb1bccb2019-01-17 16:18:38 -08001529 rdata->iov[0].iov_len = server->vals->header_preamble_size;
1530 rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1531 rdata->iov[1].iov_len =
1532 server->total_read - server->vals->header_preamble_size;
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001533 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1534 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1535 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1536 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1537
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001538 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001539 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001540 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001541 cifs_dbg(FYI, "%s: server returned error %d\n",
1542 __func__, rdata->result);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001543 /* normal error on read response */
1544 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545 }
1546
1547 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001548 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001549 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1550 __func__, server->total_read,
1551 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001552 rdata->result = -EIO;
1553 return cifs_readv_discard(server, mid);
1554 }
1555
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001556 data_offset = server->ops->read_data_offset(buf) +
1557 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558 if (data_offset < server->total_read) {
1559 /*
1560 * win2k8 sometimes sends an offset of 0 when the read
1561 * is beyond the EOF. Treat it as if the data starts just after
1562 * the header.
1563 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001564 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1565 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001566 data_offset = server->total_read;
1567 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1568 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001569 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1570 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001571 rdata->result = -EIO;
1572 return cifs_readv_discard(server, mid);
1573 }
1574
Joe Perchesf96637b2013-05-04 22:12:25 -05001575 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1576 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577
1578 len = data_offset - server->total_read;
1579 if (len > 0) {
1580 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001581 length = cifs_read_from_socket(server,
1582 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001583 if (length < 0)
1584 return length;
1585 server->total_read += length;
1586 }
1587
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001588 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001589#ifdef CONFIG_CIFS_SMB_DIRECT
1590 use_rdma_mr = rdata->mr;
1591#endif
1592 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1593 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001594 /* data_len is corrupt -- discard frame */
1595 rdata->result = -EIO;
1596 return cifs_readv_discard(server, mid);
1597 }
1598
Jeff Layton8321fec2012-09-19 06:22:32 -07001599 length = rdata->read_into_pages(server, rdata, data_len);
1600 if (length < 0)
1601 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602
Jeff Layton8321fec2012-09-19 06:22:32 -07001603 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001604
Joe Perchesf96637b2013-05-04 22:12:25 -05001605 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1606 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001607
1608 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001609 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001610 return cifs_readv_discard(server, mid);
1611
1612 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001613 mid->resp_buf = server->smallbuf;
1614 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001615 return length;
1616}
1617
1618static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001619cifs_readv_callback(struct mid_q_entry *mid)
1620{
1621 struct cifs_readdata *rdata = mid->callback_data;
1622 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1623 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001624 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1625 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001626 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001627 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001628 .rq_npages = rdata->nr_pages,
1629 .rq_pagesz = rdata->pagesz,
1630 .rq_tailsz = rdata->tailsz };
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001631 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001632
Joe Perchesf96637b2013-05-04 22:12:25 -05001633 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1634 __func__, mid->mid, mid->mid_state, rdata->result,
1635 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001636
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001637 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001638 case MID_RESPONSE_RECEIVED:
1639 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001640 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001641 int rc = 0;
1642
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001643 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001644 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001645 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001646 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1647 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001648 }
1649 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001650 task_io_account_read(rdata->got_bytes);
1651 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001652 break;
1653 case MID_REQUEST_SUBMITTED:
1654 case MID_RETRY_NEEDED:
1655 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001656 if (server->sign && rdata->got_bytes)
1657 /* reset bytes number since we can not check a sign */
1658 rdata->got_bytes = 0;
1659 /* FIXME: should this be counted toward the initiating task? */
1660 task_io_account_read(rdata->got_bytes);
1661 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001662 break;
1663 default:
1664 rdata->result = -EIO;
1665 }
1666
Jeff Laytonda472fc2012-03-23 14:40:53 -04001667 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001668 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001669 add_credits(server, &credits, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001670}
1671
1672/* cifs_async_readv - send an async write, and set up mid to handle result */
1673int
1674cifs_async_readv(struct cifs_readdata *rdata)
1675{
1676 int rc;
1677 READ_REQ *smb = NULL;
1678 int wct;
1679 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001680 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1681 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001682
Joe Perchesf96637b2013-05-04 22:12:25 -05001683 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1684 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001685
1686 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1687 wct = 12;
1688 else {
1689 wct = 10; /* old style read */
1690 if ((rdata->offset >> 32) > 0) {
1691 /* can not handle this big offset for old */
1692 return -EIO;
1693 }
1694 }
1695
1696 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1697 if (rc)
1698 return rc;
1699
1700 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1701 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1702
1703 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001704 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001705 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1706 if (wct == 12)
1707 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1708 smb->Remaining = 0;
1709 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1710 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1711 if (wct == 12)
1712 smb->ByteCount = 0;
1713 else {
1714 /* old style read */
1715 struct smb_com_readx_req *smbr =
1716 (struct smb_com_readx_req *)smb;
1717 smbr->ByteCount = 0;
1718 }
1719
1720 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001721 rdata->iov[0].iov_base = smb;
1722 rdata->iov[0].iov_len = 4;
1723 rdata->iov[1].iov_base = (char *)smb + 4;
1724 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001725
Jeff Layton6993f742012-05-16 07:13:17 -04001726 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001727 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08001728 cifs_readv_callback, NULL, rdata, 0, NULL);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001729
1730 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001731 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001732 else
1733 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001734
1735 cifs_small_buf_release(smb);
1736 return rc;
1737}
1738
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001740CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1741 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742{
1743 int rc = -EACCES;
1744 READ_REQ *pSMB = NULL;
1745 READ_RSP *pSMBr = NULL;
1746 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001747 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001748 int resp_buf_type = 0;
1749 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001750 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001751 __u32 pid = io_parms->pid;
1752 __u16 netfid = io_parms->netfid;
1753 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001754 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001755 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
Joe Perchesf96637b2013-05-04 22:12:25 -05001757 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001758 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001759 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001760 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001761 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001762 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001763 /* can not handle this big offset for old */
1764 return -EIO;
1765 }
1766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001769 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 if (rc)
1771 return rc;
1772
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001773 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1774 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1775
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 /* tcon and ses pointer are checked in smb_init */
1777 if (tcon->ses->server == NULL)
1778 return -ECONNABORTED;
1779
Steve Frenchec637e32005-12-12 20:53:18 -08001780 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001782 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001783 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001784 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 pSMB->Remaining = 0;
1787 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1788 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001789 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001790 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1791 else {
1792 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001793 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001794 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001795 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001796 }
Steve Frenchec637e32005-12-12 20:53:18 -08001797
1798 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001799 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001800 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1801 CIFS_LOG_ERROR, &rsp_iov);
1802 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001803 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001804 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001806 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 } else {
1808 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1809 data_length = data_length << 16;
1810 data_length += le16_to_cpu(pSMBr->DataLength);
1811 *nbytes = data_length;
1812
1813 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001814 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001816 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001817 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 rc = -EIO;
1819 *nbytes = 0;
1820 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001821 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001822 le16_to_cpu(pSMBr->DataOffset);
1823/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001824 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001825 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001826 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001827 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001828 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 }
1830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
Steve French790fe572007-07-07 19:25:05 +00001832 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001833 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001834 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001835 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001836 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001837 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001838 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001839 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001840 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001841 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001842
1843 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 since file handle passed in no longer valid */
1845 return rc;
1846}
1847
Steve Frenchec637e32005-12-12 20:53:18 -08001848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001850CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001851 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852{
1853 int rc = -EACCES;
1854 WRITE_REQ *pSMB = NULL;
1855 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001856 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 __u32 bytes_sent;
1858 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001859 __u32 pid = io_parms->pid;
1860 __u16 netfid = io_parms->netfid;
1861 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001862 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001863 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
Steve Frencha24e2d72010-04-03 17:20:21 +00001865 *nbytes = 0;
1866
Joe Perchesf96637b2013-05-04 22:12:25 -05001867 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001868 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001869 return -ECONNABORTED;
1870
Steve French790fe572007-07-07 19:25:05 +00001871 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001872 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001873 else {
Steve French1c955182005-08-30 20:58:07 -07001874 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001875 if ((offset >> 32) > 0) {
1876 /* can not handle big offset for old srv */
1877 return -EIO;
1878 }
1879 }
Steve French1c955182005-08-30 20:58:07 -07001880
1881 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 (void **) &pSMBr);
1883 if (rc)
1884 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001885
1886 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1887 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1888
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 /* tcon and ses pointer are checked in smb_init */
1890 if (tcon->ses->server == NULL)
1891 return -ECONNABORTED;
1892
1893 pSMB->AndXCommand = 0xFF; /* none */
1894 pSMB->Fid = netfid;
1895 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001896 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001897 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001898
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 pSMB->Reserved = 0xFFFFFFFF;
1900 pSMB->WriteMode = 0;
1901 pSMB->Remaining = 0;
1902
Steve French50c2f752007-07-13 00:33:32 +00001903 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 can send more if LARGE_WRITE_X capability returned by the server and if
1905 our buffer is big enough or if we convert to iovecs on socket writes
1906 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001907 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1909 } else {
1910 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1911 & ~0xFF;
1912 }
1913
1914 if (bytes_sent > count)
1915 bytes_sent = count;
1916 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001917 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001918 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001919 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001920 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 /* No buffer */
1922 cifs_buf_release(pSMB);
1923 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001924 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001925 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001926 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001927 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001928 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1931 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001932 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001933
Steve French790fe572007-07-07 19:25:05 +00001934 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001935 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001936 else { /* old style write has byte count 4 bytes earlier
1937 so 4 bytes pad */
1938 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001939 (struct smb_com_writex_req *)pSMB;
1940 pSMBW->ByteCount = cpu_to_le16(byte_count);
1941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
1943 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001945 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001947 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 } else {
1949 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1950 *nbytes = (*nbytes) << 16;
1951 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301952
1953 /*
1954 * Mask off high 16 bits when bytes written as returned by the
1955 * server is greater than bytes requested by the client. Some
1956 * OS/2 servers are known to set incorrect CountHigh values.
1957 */
1958 if (*nbytes > count)
1959 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 }
1961
1962 cifs_buf_release(pSMB);
1963
Steve French50c2f752007-07-13 00:33:32 +00001964 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 since file handle passed in no longer valid */
1966
1967 return rc;
1968}
1969
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001970void
1971cifs_writedata_release(struct kref *refcount)
1972{
1973 struct cifs_writedata *wdata = container_of(refcount,
1974 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001975#ifdef CONFIG_CIFS_SMB_DIRECT
1976 if (wdata->mr) {
1977 smbd_deregister_mr(wdata->mr);
1978 wdata->mr = NULL;
1979 }
1980#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001981
1982 if (wdata->cfile)
1983 cifsFileInfo_put(wdata->cfile);
1984
Long Li8e7360f2018-05-30 12:47:56 -07001985 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001986 kfree(wdata);
1987}
1988
1989/*
1990 * Write failed with a retryable error. Resend the write request. It's also
1991 * possible that the page was redirtied so re-clean the page.
1992 */
1993static void
1994cifs_writev_requeue(struct cifs_writedata *wdata)
1995{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001996 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001997 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001998 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001999 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002000
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002001 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
2002 i = 0;
2003 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002004 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002005 struct cifs_writedata *wdata2;
2006 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002007
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002008 wsize = server->ops->wp_retry_size(inode);
2009 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002010 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002011 if (!nr_pages) {
2012 rc = -ENOTSUPP;
2013 break;
2014 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002015 cur_len = nr_pages * PAGE_SIZE;
2016 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002017 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002018 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002019 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002020 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06002021 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002022
2023 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2024 if (!wdata2) {
2025 rc = -ENOMEM;
2026 break;
2027 }
2028
2029 for (j = 0; j < nr_pages; j++) {
2030 wdata2->pages[j] = wdata->pages[i + j];
2031 lock_page(wdata2->pages[j]);
2032 clear_page_dirty_for_io(wdata2->pages[j]);
2033 }
2034
2035 wdata2->sync_mode = wdata->sync_mode;
2036 wdata2->nr_pages = nr_pages;
2037 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002038 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002039 wdata2->tailsz = tailsz;
2040 wdata2->bytes = cur_len;
2041
Aurelien Aptel86f740f2020-02-21 11:19:06 +01002042 rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002043 &wdata2->cfile);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002044 if (!wdata2->cfile) {
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002045 cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
2046 rc);
2047 if (!is_retryable_error(rc))
2048 rc = -EBADF;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002049 } else {
2050 wdata2->pid = wdata2->cfile->pid;
2051 rc = server->ops->async_writev(wdata2,
2052 cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002053 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002054
2055 for (j = 0; j < nr_pages; j++) {
2056 unlock_page(wdata2->pages[j]);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002057 if (rc != 0 && !is_retryable_error(rc)) {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002058 SetPageError(wdata2->pages[j]);
2059 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002060 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002061 }
2062 }
2063
Adam McCoya4813792020-05-13 11:53:30 +00002064 kref_put(&wdata2->refcount, cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002065 if (rc) {
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002066 if (is_retryable_error(rc))
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002067 continue;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002068 i += nr_pages;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002069 break;
2070 }
2071
2072 rest_len -= cur_len;
2073 i += nr_pages;
2074 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002075
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002076 /* cleanup remaining pages from the original wdata */
2077 for (; i < wdata->nr_pages; i++) {
2078 SetPageError(wdata->pages[i]);
2079 end_page_writeback(wdata->pages[i]);
2080 put_page(wdata->pages[i]);
2081 }
2082
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002083 if (rc != 0 && !is_retryable_error(rc))
2084 mapping_set_error(inode->i_mapping, rc);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002085 kref_put(&wdata->refcount, cifs_writedata_release);
2086}
2087
Jeff Laytonc2e87642012-03-23 14:40:55 -04002088void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002089cifs_writev_complete(struct work_struct *work)
2090{
2091 struct cifs_writedata *wdata = container_of(work,
2092 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002093 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094 int i = 0;
2095
2096 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002097 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002098 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002099 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002100 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2101 wdata->bytes);
2102 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2103 return cifs_writev_requeue(wdata);
2104
2105 for (i = 0; i < wdata->nr_pages; i++) {
2106 struct page *page = wdata->pages[i];
2107 if (wdata->result == -EAGAIN)
2108 __set_page_dirty_nobuffers(page);
2109 else if (wdata->result < 0)
2110 SetPageError(page);
2111 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002112 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002113 }
2114 if (wdata->result != -EAGAIN)
2115 mapping_set_error(inode->i_mapping, wdata->result);
2116 kref_put(&wdata->refcount, cifs_writedata_release);
2117}
2118
2119struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002120cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002121{
Long Li8e7360f2018-05-30 12:47:56 -07002122 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002123 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002124 if (pages)
2125 return cifs_writedata_direct_alloc(pages, complete);
2126
2127 return NULL;
2128}
2129
2130struct cifs_writedata *
2131cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2132{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002133 struct cifs_writedata *wdata;
2134
Long Li8e7360f2018-05-30 12:47:56 -07002135 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002136 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002137 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002138 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002139 INIT_LIST_HEAD(&wdata->list);
2140 init_completion(&wdata->done);
2141 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002142 }
2143 return wdata;
2144}
2145
2146/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002147 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002148 * workqueue completion task.
2149 */
2150static void
2151cifs_writev_callback(struct mid_q_entry *mid)
2152{
2153 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002154 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002155 unsigned int written;
2156 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002157 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002158
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002159 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002160 case MID_RESPONSE_RECEIVED:
2161 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2162 if (wdata->result != 0)
2163 break;
2164
2165 written = le16_to_cpu(smb->CountHigh);
2166 written <<= 16;
2167 written += le16_to_cpu(smb->Count);
2168 /*
2169 * Mask off high 16 bits when bytes written as returned
2170 * by the server is greater than bytes requested by the
2171 * client. OS/2 servers are known to set incorrect
2172 * CountHigh values.
2173 */
2174 if (written > wdata->bytes)
2175 written &= 0xFFFF;
2176
2177 if (written < wdata->bytes)
2178 wdata->result = -ENOSPC;
2179 else
2180 wdata->bytes = written;
2181 break;
2182 case MID_REQUEST_SUBMITTED:
2183 case MID_RETRY_NEEDED:
2184 wdata->result = -EAGAIN;
2185 break;
2186 default:
2187 wdata->result = -EIO;
2188 break;
2189 }
2190
Jeff Laytonda472fc2012-03-23 14:40:53 -04002191 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002192 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002193 add_credits(tcon->ses->server, &credits, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002194}
2195
2196/* cifs_async_writev - send an async write, and set up mid to handle result */
2197int
Steve French4a5c80d2014-02-07 20:45:12 -06002198cifs_async_writev(struct cifs_writedata *wdata,
2199 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002200{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002201 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002202 WRITE_REQ *smb = NULL;
2203 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002204 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002205 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002206 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002207
2208 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2209 wct = 14;
2210 } else {
2211 wct = 12;
2212 if (wdata->offset >> 32 > 0) {
2213 /* can not handle big offset for old srv */
2214 return -EIO;
2215 }
2216 }
2217
2218 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2219 if (rc)
2220 goto async_writev_out;
2221
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002222 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2223 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002224
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002225 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002226 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002227 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2228 if (wct == 14)
2229 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2230 smb->Reserved = 0xFFFFFFFF;
2231 smb->WriteMode = 0;
2232 smb->Remaining = 0;
2233
2234 smb->DataOffset =
2235 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2236
2237 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002238 iov[0].iov_len = 4;
2239 iov[0].iov_base = smb;
2240 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2241 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002242
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002243 rqst.rq_iov = iov;
2244 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002245 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002246 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002247 rqst.rq_npages = wdata->nr_pages;
2248 rqst.rq_pagesz = wdata->pagesz;
2249 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002250
Joe Perchesf96637b2013-05-04 22:12:25 -05002251 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2252 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002253
2254 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2255 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2256
2257 if (wct == 14) {
2258 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2259 put_bcc(wdata->bytes + 1, &smb->hdr);
2260 } else {
2261 /* wct == 12 */
2262 struct smb_com_writex_req *smbw =
2263 (struct smb_com_writex_req *)smb;
2264 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2265 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002266 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002267 }
2268
2269 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002270 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08002271 cifs_writev_callback, NULL, wdata, 0, NULL);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002272
2273 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002274 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002275 else
Steve French4a5c80d2014-02-07 20:45:12 -06002276 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002277
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002278async_writev_out:
2279 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002280 return rc;
2281}
2282
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002283int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002284CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002285 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
Colin Ian King136a5dc2020-05-27 13:50:31 +01002287 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002289 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002290 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002291 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002292 __u32 pid = io_parms->pid;
2293 __u16 netfid = io_parms->netfid;
2294 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002295 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002296 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002297 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002299 *nbytes = 0;
2300
Joe Perchesf96637b2013-05-04 22:12:25 -05002301 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002302
Steve French4c3130e2008-12-09 00:28:16 +00002303 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002304 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002305 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002306 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002307 if ((offset >> 32) > 0) {
2308 /* can not handle big offset for old srv */
2309 return -EIO;
2310 }
2311 }
Steve French8cc64c62005-10-03 13:49:43 -07002312 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 if (rc)
2314 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002315
2316 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2317 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2318
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 /* tcon and ses pointer are checked in smb_init */
2320 if (tcon->ses->server == NULL)
2321 return -ECONNABORTED;
2322
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002323 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 pSMB->Fid = netfid;
2325 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002326 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002327 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 pSMB->Reserved = 0xFFFFFFFF;
2329 pSMB->WriteMode = 0;
2330 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002331
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002333 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334
Steve French3e844692005-10-03 13:37:24 -07002335 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2336 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002337 /* header + 1 byte pad */
2338 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002339 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002340 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002341 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002342 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002343 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002344 pSMB->ByteCount = cpu_to_le16(count + 1);
2345 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002346 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002347 (struct smb_com_writex_req *)pSMB;
2348 pSMBW->ByteCount = cpu_to_le16(count + 5);
2349 }
Steve French3e844692005-10-03 13:37:24 -07002350 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002351 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002352 iov[0].iov_len = smb_hdr_len + 4;
2353 else /* wct == 12 pad bigger by four bytes */
2354 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002355
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002356 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2357 &rsp_iov);
2358 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002359 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002361 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002362 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002363 /* presumably this can not happen, but best to be safe */
2364 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002365 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002366 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002367 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2368 *nbytes = (*nbytes) << 16;
2369 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302370
2371 /*
2372 * Mask off high 16 bits when bytes written as returned by the
2373 * server is greater than bytes requested by the client. OS/2
2374 * servers are known to set incorrect CountHigh values.
2375 */
2376 if (*nbytes > count)
2377 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002380 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Steve French50c2f752007-07-13 00:33:32 +00002382 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 since file handle passed in no longer valid */
2384
2385 return rc;
2386}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002387
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002388int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2389 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002390 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2391{
2392 int rc = 0;
2393 LOCK_REQ *pSMB = NULL;
2394 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002395 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002396 int resp_buf_type;
2397 __u16 count;
2398
Joe Perchesf96637b2013-05-04 22:12:25 -05002399 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2400 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002401
2402 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2403 if (rc)
2404 return rc;
2405
2406 pSMB->Timeout = 0;
2407 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2408 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2409 pSMB->LockType = lock_type;
2410 pSMB->AndXCommand = 0xFF; /* none */
2411 pSMB->Fid = netfid; /* netfid stays le */
2412
2413 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2414 inc_rfc1001_len(pSMB, count);
2415 pSMB->ByteCount = cpu_to_le16(count);
2416
2417 iov[0].iov_base = (char *)pSMB;
2418 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2419 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2420 iov[1].iov_base = (char *)buf;
2421 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2422
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002423 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002424 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
2425 CIFS_NO_RSP_BUF, &rsp_iov);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002426 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002427 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002428 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002429
2430 return rc;
2431}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002434CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002435 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002437 const __u32 numLock, const __u8 lockType,
2438 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439{
2440 int rc = 0;
2441 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002442/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002444 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 __u16 count;
2446
Joe Perchesf96637b2013-05-04 22:12:25 -05002447 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2448 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002449 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2450
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 if (rc)
2452 return rc;
2453
Steve French790fe572007-07-07 19:25:05 +00002454 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002455 /* no response expected */
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002456 flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002458 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002459 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2461 } else {
2462 pSMB->Timeout = 0;
2463 }
2464
2465 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2466 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2467 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002468 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 pSMB->AndXCommand = 0xFF; /* none */
2470 pSMB->Fid = smb_file_id; /* netfid stays le */
2471
Steve French790fe572007-07-07 19:25:05 +00002472 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002473 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 /* BB where to store pid high? */
2475 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2476 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2477 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2478 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2479 count = sizeof(LOCKING_ANDX_RANGE);
2480 } else {
2481 /* oplock break */
2482 count = 0;
2483 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002484 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 pSMB->ByteCount = cpu_to_le16(count);
2486
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002487 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002488 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002489 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002490 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002491 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002492 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002493 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002494 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002495 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
Steve French50c2f752007-07-13 00:33:32 +00002497 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 since file handle passed in no longer valid */
2499 return rc;
2500}
2501
2502int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002503CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002504 const __u16 smb_file_id, const __u32 netpid,
2505 const loff_t start_offset, const __u64 len,
2506 struct file_lock *pLockData, const __u16 lock_type,
2507 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002508{
2509 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2510 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002511 struct cifs_posix_lock *parm_data;
2512 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002513 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002514 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002515 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002516 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002517 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002518 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002519
Joe Perchesf96637b2013-05-04 22:12:25 -05002520 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002521
Steve French08547b02006-02-28 22:39:25 +00002522 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2523
2524 if (rc)
2525 return rc;
2526
2527 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2528
Steve French50c2f752007-07-13 00:33:32 +00002529 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002530 pSMB->MaxSetupCount = 0;
2531 pSMB->Reserved = 0;
2532 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002533 pSMB->Reserved2 = 0;
2534 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2535 offset = param_offset + params;
2536
Steve French08547b02006-02-28 22:39:25 +00002537 count = sizeof(struct cifs_posix_lock);
2538 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002539 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002540 pSMB->SetupCount = 1;
2541 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002542 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002543 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2544 else
2545 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2546 byte_count = 3 /* pad */ + params + count;
2547 pSMB->DataCount = cpu_to_le16(count);
2548 pSMB->ParameterCount = cpu_to_le16(params);
2549 pSMB->TotalDataCount = pSMB->DataCount;
2550 pSMB->TotalParameterCount = pSMB->ParameterCount;
2551 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002552 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002553 (((char *) &pSMB->hdr.Protocol) + offset);
2554
2555 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002556 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002557 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002558 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002559 pSMB->Timeout = cpu_to_le32(-1);
2560 } else
2561 pSMB->Timeout = 0;
2562
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002563 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002564 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002565 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002566
2567 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002568 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002569 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2570 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002571 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002572 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002573 if (waitFlag) {
2574 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2575 (struct smb_hdr *) pSMBr, &bytes_returned);
2576 } else {
Steve French133672e2007-11-13 22:41:37 +00002577 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002578 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002579 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002580 &resp_buf_type, timeout, &rsp_iov);
2581 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002582 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002583 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002584
Steve French08547b02006-02-28 22:39:25 +00002585 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002586 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002587 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002588 /* lock structure can be returned on get */
2589 __u16 data_offset;
2590 __u16 data_count;
2591 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002592
Jeff Layton820a8032011-05-04 08:05:26 -04002593 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002594 rc = -EIO; /* bad smb */
2595 goto plk_err_exit;
2596 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002597 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2598 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002599 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002600 rc = -EIO;
2601 goto plk_err_exit;
2602 }
2603 parm_data = (struct cifs_posix_lock *)
2604 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002605 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002606 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002607 else {
2608 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002609 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002610 pLockData->fl_type = F_RDLCK;
2611 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002612 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002613 pLockData->fl_type = F_WRLCK;
2614
Steve French5443d132011-03-13 05:08:25 +00002615 pLockData->fl_start = le64_to_cpu(parm_data->start);
2616 pLockData->fl_end = pLockData->fl_start +
2617 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002618 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002619 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002620 }
Steve French50c2f752007-07-13 00:33:32 +00002621
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002622plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002623 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002624
Steve French08547b02006-02-28 22:39:25 +00002625 /* Note: On -EAGAIN error only caller can retry on handle based calls
2626 since file handle passed in no longer valid */
2627
2628 return rc;
2629}
2630
2631
2632int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002633CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634{
2635 int rc = 0;
2636 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002637 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638
2639/* do not retry on dead session on close */
2640 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002641 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 return 0;
2643 if (rc)
2644 return rc;
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002647 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002649 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002650 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002651 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002653 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002655 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 }
2657 }
2658
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002660 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 rc = 0;
2662
2663 return rc;
2664}
2665
2666int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002667CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002668{
2669 int rc = 0;
2670 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002671 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002672
2673 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2674 if (rc)
2675 return rc;
2676
2677 pSMB->FileID = (__u16) smb_file_id;
2678 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002679 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002680 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002681 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002682 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002683 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002684
2685 return rc;
2686}
2687
2688int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002689CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002690 const char *from_name, const char *to_name,
2691 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692{
2693 int rc = 0;
2694 RENAME_REQ *pSMB = NULL;
2695 RENAME_RSP *pSMBr = NULL;
2696 int bytes_returned;
2697 int name_len, name_len2;
2698 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002699 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Joe Perchesf96637b2013-05-04 22:12:25 -05002701 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702renameRetry:
2703 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2704 (void **) &pSMBr);
2705 if (rc)
2706 return rc;
2707
2708 pSMB->BufferFormat = 0x04;
2709 pSMB->SearchAttributes =
2710 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2711 ATTR_DIRECTORY);
2712
2713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002714 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2715 from_name, PATH_MAX,
2716 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 name_len++; /* trailing null */
2718 name_len *= 2;
2719 pSMB->OldFileName[name_len] = 0x04; /* pad */
2720 /* protocol requires ASCII signature byte on Unicode string */
2721 pSMB->OldFileName[name_len + 1] = 0x00;
2722 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002723 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002724 to_name, PATH_MAX, cifs_sb->local_nls,
2725 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2727 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002728 } else {
2729 name_len = copy_path_name(pSMB->OldFileName, from_name);
2730 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 name_len2++; /* signature byte */
2733 }
2734
2735 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002736 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 pSMB->ByteCount = cpu_to_le16(count);
2738
2739 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2740 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002741 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002742 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002743 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 cifs_buf_release(pSMB);
2746
2747 if (rc == -EAGAIN)
2748 goto renameRetry;
2749
2750 return rc;
2751}
2752
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002753int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002754 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002755 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756{
2757 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2758 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002759 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 char *data_offset;
2761 char dummy_string[30];
2762 int rc = 0;
2763 int bytes_returned = 0;
2764 int len_of_str;
2765 __u16 params, param_offset, offset, count, byte_count;
2766
Joe Perchesf96637b2013-05-04 22:12:25 -05002767 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2769 (void **) &pSMBr);
2770 if (rc)
2771 return rc;
2772
2773 params = 6;
2774 pSMB->MaxSetupCount = 0;
2775 pSMB->Reserved = 0;
2776 pSMB->Flags = 0;
2777 pSMB->Timeout = 0;
2778 pSMB->Reserved2 = 0;
2779 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2780 offset = param_offset + params;
2781
2782 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2783 rename_info = (struct set_file_rename *) data_offset;
2784 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002785 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 pSMB->SetupCount = 1;
2787 pSMB->Reserved3 = 0;
2788 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2789 byte_count = 3 /* pad */ + params;
2790 pSMB->ParameterCount = cpu_to_le16(params);
2791 pSMB->TotalParameterCount = pSMB->ParameterCount;
2792 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2793 pSMB->DataOffset = cpu_to_le16(offset);
2794 /* construct random name ".cifs_tmp<inodenum><mid>" */
2795 rename_info->overwrite = cpu_to_le32(1);
2796 rename_info->root_fid = 0;
2797 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002798 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002799 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002800 len_of_str =
2801 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002802 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002804 len_of_str =
2805 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002806 target_name, PATH_MAX, nls_codepage,
2807 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 }
2809 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002810 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 byte_count += count;
2812 pSMB->DataCount = cpu_to_le16(count);
2813 pSMB->TotalDataCount = pSMB->DataCount;
2814 pSMB->Fid = netfid;
2815 pSMB->InformationLevel =
2816 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2817 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002818 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 pSMB->ByteCount = cpu_to_le16(byte_count);
2820 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002822 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002823 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002824 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2825 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002826
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 cifs_buf_release(pSMB);
2828
2829 /* Note: On -EAGAIN error only caller can retry on handle based calls
2830 since file handle passed in no longer valid */
2831
2832 return rc;
2833}
2834
2835int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002836CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2837 const char *fromName, const __u16 target_tid, const char *toName,
2838 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839{
2840 int rc = 0;
2841 COPY_REQ *pSMB = NULL;
2842 COPY_RSP *pSMBr = NULL;
2843 int bytes_returned;
2844 int name_len, name_len2;
2845 __u16 count;
2846
Joe Perchesf96637b2013-05-04 22:12:25 -05002847 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848copyRetry:
2849 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2850 (void **) &pSMBr);
2851 if (rc)
2852 return rc;
2853
2854 pSMB->BufferFormat = 0x04;
2855 pSMB->Tid2 = target_tid;
2856
2857 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2858
2859 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002860 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2861 fromName, PATH_MAX, nls_codepage,
2862 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 name_len++; /* trailing null */
2864 name_len *= 2;
2865 pSMB->OldFileName[name_len] = 0x04; /* pad */
2866 /* protocol requires ASCII signature byte on Unicode string */
2867 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002868 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002869 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2870 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2872 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002873 } else {
2874 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002876 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 name_len2++; /* signature byte */
2878 }
2879
2880 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002881 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 pSMB->ByteCount = cpu_to_le16(count);
2883
2884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2886 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002887 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2888 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 }
Steve French0d817bc2008-05-22 02:02:03 +00002890 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
2892 if (rc == -EAGAIN)
2893 goto copyRetry;
2894
2895 return rc;
2896}
2897
2898int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002899CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002901 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902{
2903 TRANSACTION2_SPI_REQ *pSMB = NULL;
2904 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2905 char *data_offset;
2906 int name_len;
2907 int name_len_target;
2908 int rc = 0;
2909 int bytes_returned = 0;
2910 __u16 params, param_offset, offset, byte_count;
2911
Joe Perchesf96637b2013-05-04 22:12:25 -05002912 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913createSymLinkRetry:
2914 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2915 (void **) &pSMBr);
2916 if (rc)
2917 return rc;
2918
2919 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2920 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002921 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2922 /* find define for this maxpathcomponent */
2923 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 name_len++; /* trailing null */
2925 name_len *= 2;
2926
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002927 } else {
2928 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 }
2930 params = 6 + name_len;
2931 pSMB->MaxSetupCount = 0;
2932 pSMB->Reserved = 0;
2933 pSMB->Flags = 0;
2934 pSMB->Timeout = 0;
2935 pSMB->Reserved2 = 0;
2936 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002937 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 offset = param_offset + params;
2939
2940 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2941 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2942 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002943 cifsConvertToUTF16((__le16 *) data_offset, toName,
2944 /* find define for this maxpathcomponent */
2945 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 name_len_target++; /* trailing null */
2947 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002948 } else {
2949 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 }
2951
2952 pSMB->MaxParameterCount = cpu_to_le16(2);
2953 /* BB find exact max on data count below from sess */
2954 pSMB->MaxDataCount = cpu_to_le16(1000);
2955 pSMB->SetupCount = 1;
2956 pSMB->Reserved3 = 0;
2957 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2958 byte_count = 3 /* pad */ + params + name_len_target;
2959 pSMB->DataCount = cpu_to_le16(name_len_target);
2960 pSMB->ParameterCount = cpu_to_le16(params);
2961 pSMB->TotalDataCount = pSMB->DataCount;
2962 pSMB->TotalParameterCount = pSMB->ParameterCount;
2963 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2964 pSMB->DataOffset = cpu_to_le16(offset);
2965 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2966 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002967 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 pSMB->ByteCount = cpu_to_le16(byte_count);
2969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002971 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002972 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002973 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2974 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
Steve French0d817bc2008-05-22 02:02:03 +00002976 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
2978 if (rc == -EAGAIN)
2979 goto createSymLinkRetry;
2980
2981 return rc;
2982}
2983
2984int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002985CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002987 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988{
2989 TRANSACTION2_SPI_REQ *pSMB = NULL;
2990 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2991 char *data_offset;
2992 int name_len;
2993 int name_len_target;
2994 int rc = 0;
2995 int bytes_returned = 0;
2996 __u16 params, param_offset, offset, byte_count;
2997
Joe Perchesf96637b2013-05-04 22:12:25 -05002998 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999createHardLinkRetry:
3000 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3001 (void **) &pSMBr);
3002 if (rc)
3003 return rc;
3004
3005 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06003006 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
3007 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 name_len++; /* trailing null */
3009 name_len *= 2;
3010
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003011 } else {
3012 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 }
3014 params = 6 + name_len;
3015 pSMB->MaxSetupCount = 0;
3016 pSMB->Reserved = 0;
3017 pSMB->Flags = 0;
3018 pSMB->Timeout = 0;
3019 pSMB->Reserved2 = 0;
3020 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003021 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 offset = param_offset + params;
3023
3024 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3026 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003027 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3028 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 name_len_target++; /* trailing null */
3030 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003031 } else {
3032 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 }
3034
3035 pSMB->MaxParameterCount = cpu_to_le16(2);
3036 /* BB find exact max on data count below from sess*/
3037 pSMB->MaxDataCount = cpu_to_le16(1000);
3038 pSMB->SetupCount = 1;
3039 pSMB->Reserved3 = 0;
3040 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3041 byte_count = 3 /* pad */ + params + name_len_target;
3042 pSMB->ParameterCount = cpu_to_le16(params);
3043 pSMB->TotalParameterCount = pSMB->ParameterCount;
3044 pSMB->DataCount = cpu_to_le16(name_len_target);
3045 pSMB->TotalDataCount = pSMB->DataCount;
3046 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3047 pSMB->DataOffset = cpu_to_le16(offset);
3048 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3049 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003050 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pSMB->ByteCount = cpu_to_le16(byte_count);
3052 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3053 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003054 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003055 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003056 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3057 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
3059 cifs_buf_release(pSMB);
3060 if (rc == -EAGAIN)
3061 goto createHardLinkRetry;
3062
3063 return rc;
3064}
3065
3066int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003067CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003068 const char *from_name, const char *to_name,
3069 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070{
3071 int rc = 0;
3072 NT_RENAME_REQ *pSMB = NULL;
3073 RENAME_RSP *pSMBr = NULL;
3074 int bytes_returned;
3075 int name_len, name_len2;
3076 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003077 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078
Joe Perchesf96637b2013-05-04 22:12:25 -05003079 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080winCreateHardLinkRetry:
3081
3082 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3083 (void **) &pSMBr);
3084 if (rc)
3085 return rc;
3086
3087 pSMB->SearchAttributes =
3088 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3089 ATTR_DIRECTORY);
3090 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3091 pSMB->ClusterCount = 0;
3092
3093 pSMB->BufferFormat = 0x04;
3094
3095 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3096 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003097 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3098 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 name_len++; /* trailing null */
3100 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003101
3102 /* protocol specifies ASCII buffer format (0x04) for unicode */
3103 pSMB->OldFileName[name_len] = 0x04;
3104 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003106 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003107 to_name, PATH_MAX, cifs_sb->local_nls,
3108 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3110 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003111 } else {
3112 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003114 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 name_len2++; /* signature byte */
3116 }
3117
3118 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003119 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 pSMB->ByteCount = cpu_to_le16(count);
3121
3122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003124 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003125 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003126 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003127
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 cifs_buf_release(pSMB);
3129 if (rc == -EAGAIN)
3130 goto winCreateHardLinkRetry;
3131
3132 return rc;
3133}
3134
3135int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003136CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003137 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003138 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139{
3140/* SMB_QUERY_FILE_UNIX_LINK */
3141 TRANSACTION2_QPI_REQ *pSMB = NULL;
3142 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3143 int rc = 0;
3144 int bytes_returned;
3145 int name_len;
3146 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003147 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148
Joe Perchesf96637b2013-05-04 22:12:25 -05003149 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150
3151querySymLinkRetry:
3152 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3153 (void **) &pSMBr);
3154 if (rc)
3155 return rc;
3156
3157 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3158 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003159 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3160 searchName, PATH_MAX, nls_codepage,
3161 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 name_len++; /* trailing null */
3163 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003164 } else {
3165 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 }
3167
3168 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3169 pSMB->TotalDataCount = 0;
3170 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003171 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 pSMB->MaxSetupCount = 0;
3173 pSMB->Reserved = 0;
3174 pSMB->Flags = 0;
3175 pSMB->Timeout = 0;
3176 pSMB->Reserved2 = 0;
3177 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003178 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 pSMB->DataCount = 0;
3180 pSMB->DataOffset = 0;
3181 pSMB->SetupCount = 1;
3182 pSMB->Reserved3 = 0;
3183 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3184 byte_count = params + 1 /* pad */ ;
3185 pSMB->TotalParameterCount = cpu_to_le16(params);
3186 pSMB->ParameterCount = pSMB->TotalParameterCount;
3187 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3188 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003189 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 pSMB->ByteCount = cpu_to_le16(byte_count);
3191
3192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3194 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003195 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 } else {
3197 /* decode response */
3198
3199 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003201 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003202 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003204 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003205 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
Jeff Layton460b9692009-04-30 07:17:56 -04003207 data_start = ((char *) &pSMBr->hdr.Protocol) +
3208 le16_to_cpu(pSMBr->t2.DataOffset);
3209
Steve French0e0d2cf2009-05-01 05:27:32 +00003210 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3211 is_unicode = true;
3212 else
3213 is_unicode = false;
3214
Steve French737b7582005-04-28 22:41:06 -07003215 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003216 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3217 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003218 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003219 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 }
3221 }
3222 cifs_buf_release(pSMB);
3223 if (rc == -EAGAIN)
3224 goto querySymLinkRetry;
3225 return rc;
3226}
3227
Steve Frenchc52a95542011-02-24 06:16:22 +00003228/*
3229 * Recent Windows versions now create symlinks more frequently
3230 * and they use the "reparse point" mechanism below. We can of course
3231 * do symlinks nicely to Samba and other servers which support the
3232 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3233 * "MF" symlinks optionally, but for recent Windows we really need to
3234 * reenable the code below and fix the cifs_symlink callers to handle this.
3235 * In the interim this code has been moved to its own config option so
3236 * it is not compiled in by default until callers fixed up and more tested.
3237 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003239CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3240 __u16 fid, char **symlinkinfo,
3241 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242{
3243 int rc = 0;
3244 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003245 struct smb_com_transaction_ioctl_req *pSMB;
3246 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003247 bool is_unicode;
3248 unsigned int sub_len;
3249 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003250 struct reparse_symlink_data *reparse_buf;
3251 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003252 __u32 data_offset, data_count;
3253 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003255 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3257 (void **) &pSMBr);
3258 if (rc)
3259 return rc;
3260
3261 pSMB->TotalParameterCount = 0 ;
3262 pSMB->TotalDataCount = 0;
3263 pSMB->MaxParameterCount = cpu_to_le32(2);
3264 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003265 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 pSMB->MaxSetupCount = 4;
3267 pSMB->Reserved = 0;
3268 pSMB->ParameterOffset = 0;
3269 pSMB->DataCount = 0;
3270 pSMB->DataOffset = 0;
3271 pSMB->SetupCount = 4;
3272 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3273 pSMB->ParameterCount = pSMB->TotalParameterCount;
3274 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3275 pSMB->IsFsctl = 1; /* FSCTL */
3276 pSMB->IsRootFlag = 0;
3277 pSMB->Fid = fid; /* file handle always le */
3278 pSMB->ByteCount = 0;
3279
3280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3281 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3282 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003283 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003284 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 }
Steve French989c7e52009-05-02 05:32:20 +00003286
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003287 data_offset = le32_to_cpu(pSMBr->DataOffset);
3288 data_count = le32_to_cpu(pSMBr->DataCount);
3289 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3290 /* BB also check enough total bytes returned */
3291 rc = -EIO; /* bad smb */
3292 goto qreparse_out;
3293 }
3294 if (!data_count || (data_count > 2048)) {
3295 rc = -EIO;
3296 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3297 goto qreparse_out;
3298 }
3299 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003300 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003301 ((char *)&pSMBr->hdr.Protocol + data_offset);
3302 if ((char *)reparse_buf >= end_of_smb) {
3303 rc = -EIO;
3304 goto qreparse_out;
3305 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003306 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3307 cifs_dbg(FYI, "NFS style reparse tag\n");
3308 posix_buf = (struct reparse_posix_data *)reparse_buf;
3309
3310 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3311 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3312 le64_to_cpu(posix_buf->InodeType));
3313 rc = -EOPNOTSUPP;
3314 goto qreparse_out;
3315 }
3316 is_unicode = true;
3317 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3318 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3319 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3320 rc = -EIO;
3321 goto qreparse_out;
3322 }
3323 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3324 sub_len, is_unicode, nls_codepage);
3325 goto qreparse_out;
3326 } else if (reparse_buf->ReparseTag !=
3327 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3328 rc = -EOPNOTSUPP;
3329 goto qreparse_out;
3330 }
3331
3332 /* Reparse tag is NTFS symlink */
3333 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3334 reparse_buf->PathBuffer;
3335 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3336 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003337 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3338 rc = -EIO;
3339 goto qreparse_out;
3340 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003341 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3342 is_unicode = true;
3343 else
3344 is_unicode = false;
3345
3346 /* BB FIXME investigate remapping reserved chars here */
3347 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3348 nls_codepage);
3349 if (!*symlinkinfo)
3350 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003352 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003354 /*
3355 * Note: On -EAGAIN error only caller can retry on handle based calls
3356 * since file handle passed in no longer valid.
3357 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 return rc;
3359}
3360
Steve Frenchc7f508a2013-10-14 15:27:32 -05003361int
3362CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3363 __u16 fid)
3364{
3365 int rc = 0;
3366 int bytes_returned;
3367 struct smb_com_transaction_compr_ioctl_req *pSMB;
3368 struct smb_com_transaction_ioctl_rsp *pSMBr;
3369
3370 cifs_dbg(FYI, "Set compression for %u\n", fid);
3371 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3372 (void **) &pSMBr);
3373 if (rc)
3374 return rc;
3375
3376 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3377
3378 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003379 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003380 pSMB->MaxParameterCount = 0;
3381 pSMB->MaxDataCount = 0;
3382 pSMB->MaxSetupCount = 4;
3383 pSMB->Reserved = 0;
3384 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003385 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003386 pSMB->DataOffset =
3387 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3388 compression_state) - 4); /* 84 */
3389 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003390 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003391 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003392 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003393 pSMB->IsFsctl = 1; /* FSCTL */
3394 pSMB->IsRootFlag = 0;
3395 pSMB->Fid = fid; /* file handle always le */
3396 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003397 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003398 inc_rfc1001_len(pSMB, 5);
3399
3400 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3401 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3402 if (rc)
3403 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3404
3405 cifs_buf_release(pSMB);
3406
3407 /*
3408 * Note: On -EAGAIN error only caller can retry on handle based calls
3409 * since file handle passed in no longer valid.
3410 */
3411 return rc;
3412}
3413
3414
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415#ifdef CONFIG_CIFS_POSIX
3416
3417/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003418static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003419 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420{
3421 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003422 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3423 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3424 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003425/*
3426 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3427 ace->e_perm, ace->e_tag, ace->e_id);
3428*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429
3430 return;
3431}
3432
3433/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003434static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3435 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436{
3437 int size = 0;
3438 int i;
3439 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003440 struct cifs_posix_ace *pACE;
3441 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003442 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
3444 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3445 return -EOPNOTSUPP;
3446
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003447 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 count = le16_to_cpu(cifs_acl->access_entry_count);
3449 pACE = &cifs_acl->ace_array[0];
3450 size = sizeof(struct cifs_posix_acl);
3451 size += sizeof(struct cifs_posix_ace) * count;
3452 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003453 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003454 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3455 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 return -EINVAL;
3457 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003458 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 count = le16_to_cpu(cifs_acl->access_entry_count);
3460 size = sizeof(struct cifs_posix_acl);
3461 size += sizeof(struct cifs_posix_ace) * count;
3462/* skip past access ACEs to get to default ACEs */
3463 pACE = &cifs_acl->ace_array[count];
3464 count = le16_to_cpu(cifs_acl->default_entry_count);
3465 size += sizeof(struct cifs_posix_ace) * count;
3466 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003467 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 return -EINVAL;
3469 } else {
3470 /* illegal type */
3471 return -EINVAL;
3472 }
3473
3474 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003475 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003476 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003477 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 return -ERANGE;
3479 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003480 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3481
Steve Frenchff7feac2005-11-15 16:45:16 -08003482 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003483 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003484 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003485 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 }
3487 }
3488 return size;
3489}
3490
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303491static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003492 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493{
Steve Frenchff7feac2005-11-15 16:45:16 -08003494 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3495 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003497 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 /* Probably no need to le convert -1 on any arch but can not hurt */
3499 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003500 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003501 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003502/*
3503 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3504 ace->e_perm, ace->e_tag, ace->e_id);
3505*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506}
3507
3508/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003509static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3510 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511{
3512 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003513 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003514 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003515 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 int count;
3517 int i;
3518
Steve French790fe572007-07-07 19:25:05 +00003519 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 return 0;
3521
3522 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003523 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3524 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003525 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003526 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3527 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 return 0;
3529 }
3530 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003531 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003532 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003533 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003534 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003535 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003536 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003537 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003538 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 return 0;
3540 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303541 for (i = 0; i < count; i++)
3542 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003543 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3545 rc += sizeof(struct cifs_posix_acl);
3546 /* BB add check to make sure ACL does not overflow SMB */
3547 }
3548 return rc;
3549}
3550
3551int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003552CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003553 const unsigned char *searchName,
3554 char *acl_inf, const int buflen, const int acl_type,
3555 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556{
3557/* SMB_QUERY_POSIX_ACL */
3558 TRANSACTION2_QPI_REQ *pSMB = NULL;
3559 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3560 int rc = 0;
3561 int bytes_returned;
3562 int name_len;
3563 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003564
Joe Perchesf96637b2013-05-04 22:12:25 -05003565 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
3567queryAclRetry:
3568 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3569 (void **) &pSMBr);
3570 if (rc)
3571 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003572
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3574 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003575 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3576 searchName, PATH_MAX, nls_codepage,
3577 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 name_len++; /* trailing null */
3579 name_len *= 2;
3580 pSMB->FileName[name_len] = 0;
3581 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003582 } else {
3583 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 }
3585
3586 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3587 pSMB->TotalDataCount = 0;
3588 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003589 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 pSMB->MaxDataCount = cpu_to_le16(4000);
3591 pSMB->MaxSetupCount = 0;
3592 pSMB->Reserved = 0;
3593 pSMB->Flags = 0;
3594 pSMB->Timeout = 0;
3595 pSMB->Reserved2 = 0;
3596 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003597 offsetof(struct smb_com_transaction2_qpi_req,
3598 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 pSMB->DataCount = 0;
3600 pSMB->DataOffset = 0;
3601 pSMB->SetupCount = 1;
3602 pSMB->Reserved3 = 0;
3603 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3604 byte_count = params + 1 /* pad */ ;
3605 pSMB->TotalParameterCount = cpu_to_le16(params);
3606 pSMB->ParameterCount = pSMB->TotalParameterCount;
3607 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3608 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003609 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 pSMB->ByteCount = cpu_to_le16(byte_count);
3611
3612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003614 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003616 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 } else {
3618 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003619
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003622 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 rc = -EIO; /* bad smb */
3624 else {
3625 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3626 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3627 rc = cifs_copy_posix_acl(acl_inf,
3628 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003629 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 }
3631 }
3632 cifs_buf_release(pSMB);
3633 if (rc == -EAGAIN)
3634 goto queryAclRetry;
3635 return rc;
3636}
3637
3638int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003639CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003640 const unsigned char *fileName,
3641 const char *local_acl, const int buflen,
3642 const int acl_type,
3643 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644{
3645 struct smb_com_transaction2_spi_req *pSMB = NULL;
3646 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3647 char *parm_data;
3648 int name_len;
3649 int rc = 0;
3650 int bytes_returned = 0;
3651 __u16 params, byte_count, data_count, param_offset, offset;
3652
Joe Perchesf96637b2013-05-04 22:12:25 -05003653 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654setAclRetry:
3655 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003656 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 if (rc)
3658 return rc;
3659 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3660 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003661 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3662 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 name_len++; /* trailing null */
3664 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003665 } else {
3666 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 }
3668 params = 6 + name_len;
3669 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003670 /* BB find max SMB size from sess */
3671 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 pSMB->MaxSetupCount = 0;
3673 pSMB->Reserved = 0;
3674 pSMB->Flags = 0;
3675 pSMB->Timeout = 0;
3676 pSMB->Reserved2 = 0;
3677 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003678 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 offset = param_offset + params;
3680 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3681 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3682
3683 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003684 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685
Steve French790fe572007-07-07 19:25:05 +00003686 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 rc = -EOPNOTSUPP;
3688 goto setACLerrorExit;
3689 }
3690 pSMB->DataOffset = cpu_to_le16(offset);
3691 pSMB->SetupCount = 1;
3692 pSMB->Reserved3 = 0;
3693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3694 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3695 byte_count = 3 /* pad */ + params + data_count;
3696 pSMB->DataCount = cpu_to_le16(data_count);
3697 pSMB->TotalDataCount = pSMB->DataCount;
3698 pSMB->ParameterCount = cpu_to_le16(params);
3699 pSMB->TotalParameterCount = pSMB->ParameterCount;
3700 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003701 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 pSMB->ByteCount = cpu_to_le16(byte_count);
3703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003705 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003706 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707
3708setACLerrorExit:
3709 cifs_buf_release(pSMB);
3710 if (rc == -EAGAIN)
3711 goto setAclRetry;
3712 return rc;
3713}
3714
Steve Frenchf654bac2005-04-28 22:41:04 -07003715/* BB fix tabs in this function FIXME BB */
3716int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003717CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003718 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003719{
Steve French50c2f752007-07-13 00:33:32 +00003720 int rc = 0;
3721 struct smb_t2_qfi_req *pSMB = NULL;
3722 struct smb_t2_qfi_rsp *pSMBr = NULL;
3723 int bytes_returned;
3724 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003725
Joe Perchesf96637b2013-05-04 22:12:25 -05003726 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003727 if (tcon == NULL)
3728 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003729
3730GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003731 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3732 (void **) &pSMBr);
3733 if (rc)
3734 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003735
Steve Frenchad7a2922008-02-07 23:25:02 +00003736 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003737 pSMB->t2.TotalDataCount = 0;
3738 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3739 /* BB find exact max data count below from sess structure BB */
3740 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3741 pSMB->t2.MaxSetupCount = 0;
3742 pSMB->t2.Reserved = 0;
3743 pSMB->t2.Flags = 0;
3744 pSMB->t2.Timeout = 0;
3745 pSMB->t2.Reserved2 = 0;
3746 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3747 Fid) - 4);
3748 pSMB->t2.DataCount = 0;
3749 pSMB->t2.DataOffset = 0;
3750 pSMB->t2.SetupCount = 1;
3751 pSMB->t2.Reserved3 = 0;
3752 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3753 byte_count = params + 1 /* pad */ ;
3754 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3755 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3756 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3757 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003758 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003759 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003760 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003761
Steve French790fe572007-07-07 19:25:05 +00003762 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3763 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3764 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003765 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003766 } else {
3767 /* decode response */
3768 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003769 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003770 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003771 /* If rc should we check for EOPNOSUPP and
3772 disable the srvino flag? or in caller? */
3773 rc = -EIO; /* bad smb */
3774 else {
3775 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3776 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3777 struct file_chattr_info *pfinfo;
3778 /* BB Do we need a cast or hash here ? */
3779 if (count != 16) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003780 cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003781 rc = -EIO;
3782 goto GetExtAttrOut;
3783 }
3784 pfinfo = (struct file_chattr_info *)
3785 (data_offset + (char *) &pSMBr->hdr.Protocol);
3786 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003787 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003788 }
3789 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003790GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003791 cifs_buf_release(pSMB);
3792 if (rc == -EAGAIN)
3793 goto GetExtAttrRetry;
3794 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003795}
3796
Steve Frenchf654bac2005-04-28 22:41:04 -07003797#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Jeff Layton79df1ba2010-12-06 12:52:08 -05003799/*
3800 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3801 * all NT TRANSACTS that we init here have total parm and data under about 400
3802 * bytes (to fit in small cifs buffer size), which is the case so far, it
3803 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3804 * returned setup area) and MaxParameterCount (returned parms size) must be set
3805 * by caller
3806 */
3807static int
3808smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003809 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003810 void **ret_buf)
3811{
3812 int rc;
3813 __u32 temp_offset;
3814 struct smb_com_ntransact_req *pSMB;
3815
3816 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3817 (void **)&pSMB);
3818 if (rc)
3819 return rc;
3820 *ret_buf = (void *)pSMB;
3821 pSMB->Reserved = 0;
3822 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3823 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003824 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003825 pSMB->ParameterCount = pSMB->TotalParameterCount;
3826 pSMB->DataCount = pSMB->TotalDataCount;
3827 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3828 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3829 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3830 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3831 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3832 pSMB->SubCommand = cpu_to_le16(sub_command);
3833 return 0;
3834}
3835
3836static int
3837validate_ntransact(char *buf, char **ppparm, char **ppdata,
3838 __u32 *pparmlen, __u32 *pdatalen)
3839{
3840 char *end_of_smb;
3841 __u32 data_count, data_offset, parm_count, parm_offset;
3842 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003843 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003844
3845 *pdatalen = 0;
3846 *pparmlen = 0;
3847
3848 if (buf == NULL)
3849 return -EINVAL;
3850
3851 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3852
Jeff Layton820a8032011-05-04 08:05:26 -04003853 bcc = get_bcc(&pSMBr->hdr);
3854 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003855 (char *)&pSMBr->ByteCount;
3856
3857 data_offset = le32_to_cpu(pSMBr->DataOffset);
3858 data_count = le32_to_cpu(pSMBr->DataCount);
3859 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3860 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3861
3862 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3863 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3864
3865 /* should we also check that parm and data areas do not overlap? */
3866 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003867 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003868 return -EINVAL;
3869 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003870 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003871 return -EINVAL;
3872 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003873 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003874 return -EINVAL;
3875 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003876 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3877 *ppdata, data_count, (data_count + *ppdata),
3878 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003879 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003880 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003881 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003882 return -EINVAL;
3883 }
3884 *pdatalen = data_count;
3885 *pparmlen = parm_count;
3886 return 0;
3887}
3888
Steve French0a4b92c2006-01-12 15:44:21 -08003889/* Get Security Descriptor (by handle) from remote server for a file or dir */
3890int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003891CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003892 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003893{
3894 int rc = 0;
3895 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003896 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003897 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003898 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003899
Joe Perchesf96637b2013-05-04 22:12:25 -05003900 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003901
Steve French630f3f0c2007-10-25 21:17:17 +00003902 *pbuflen = 0;
3903 *acl_inf = NULL;
3904
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003905 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003906 8 /* parm len */, tcon, (void **) &pSMB);
3907 if (rc)
3908 return rc;
3909
3910 pSMB->MaxParameterCount = cpu_to_le32(4);
3911 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3912 pSMB->MaxSetupCount = 0;
3913 pSMB->Fid = fid; /* file handle always le */
3914 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3915 CIFS_ACL_DACL);
3916 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003917 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003918 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003919 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003920
Steve Frencha761ac52007-10-18 21:45:27 +00003921 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003922 0, &rsp_iov);
3923 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003924 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003925 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003926 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003927 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003928 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003929 __u32 parm_len;
3930 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003931 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003932 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003933
3934/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003935 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003936 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003937 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003938 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003939 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003940
Joe Perchesf96637b2013-05-04 22:12:25 -05003941 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3942 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003943
3944 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3945 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003946 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003947 goto qsec_out;
3948 }
3949
3950/* BB check that data area is minimum length and as big as acl_len */
3951
Steve Frenchaf6f4612007-10-16 18:40:37 +00003952 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003953 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003954 cifs_dbg(VFS, "acl length %d does not match %d\n",
3955 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003956 if (*pbuflen > acl_len)
3957 *pbuflen = acl_len;
3958 }
Steve French0a4b92c2006-01-12 15:44:21 -08003959
Steve French630f3f0c2007-10-25 21:17:17 +00003960 /* check if buffer is big enough for the acl
3961 header followed by the smallest SID */
3962 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3963 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003964 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003965 rc = -EINVAL;
3966 *pbuflen = 0;
3967 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003968 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003969 if (*acl_inf == NULL) {
3970 *pbuflen = 0;
3971 rc = -ENOMEM;
3972 }
Steve French630f3f0c2007-10-25 21:17:17 +00003973 }
Steve French0a4b92c2006-01-12 15:44:21 -08003974 }
3975qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003976 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003977 return rc;
3978}
Steve French97837582007-12-31 07:47:21 +00003979
3980int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003981CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003982 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003983{
3984 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3985 int rc = 0;
3986 int bytes_returned = 0;
3987 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003988 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003989
3990setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003991 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003992 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003993 return rc;
Steve French97837582007-12-31 07:47:21 +00003994
3995 pSMB->MaxSetupCount = 0;
3996 pSMB->Reserved = 0;
3997
3998 param_count = 8;
3999 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
4000 data_count = acllen;
4001 data_offset = param_offset + param_count;
4002 byte_count = 3 /* pad */ + param_count;
4003
4004 pSMB->DataCount = cpu_to_le32(data_count);
4005 pSMB->TotalDataCount = pSMB->DataCount;
4006 pSMB->MaxParameterCount = cpu_to_le32(4);
4007 pSMB->MaxDataCount = cpu_to_le32(16384);
4008 pSMB->ParameterCount = cpu_to_le32(param_count);
4009 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4010 pSMB->TotalParameterCount = pSMB->ParameterCount;
4011 pSMB->DataOffset = cpu_to_le32(data_offset);
4012 pSMB->SetupCount = 0;
4013 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4014 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4015
4016 pSMB->Fid = fid; /* file handle always le */
4017 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004018 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004019
4020 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004021 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4022 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004023 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004024 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004025 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004026
4027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4029
Joe Perchesf96637b2013-05-04 22:12:25 -05004030 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4031 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004032 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004033 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004034 cifs_buf_release(pSMB);
4035
4036 if (rc == -EAGAIN)
4037 goto setCifsAclRetry;
4038
4039 return (rc);
4040}
4041
Steve French0a4b92c2006-01-12 15:44:21 -08004042
Steve French6b8edfe2005-08-23 20:26:03 -07004043/* Legacy Query Path Information call for lookup to old servers such
4044 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004045int
4046SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4047 const char *search_name, FILE_ALL_INFO *data,
4048 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004049{
Steve Frenchad7a2922008-02-07 23:25:02 +00004050 QUERY_INFORMATION_REQ *pSMB;
4051 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004052 int rc = 0;
4053 int bytes_returned;
4054 int name_len;
4055
Joe Perchesf96637b2013-05-04 22:12:25 -05004056 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004057QInfRetry:
4058 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004059 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004060 if (rc)
4061 return rc;
4062
4063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4064 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004065 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004066 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004067 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004068 name_len++; /* trailing null */
4069 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004070 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004071 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004072 }
4073 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004074 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004075 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004076 pSMB->ByteCount = cpu_to_le16(name_len);
4077
4078 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004079 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004080 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004081 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004082 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004083 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004084 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004085
4086 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004087 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004088 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004089 ts.tv_nsec = 0;
4090 ts.tv_sec = time;
4091 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004092 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4093 data->LastWriteTime = data->ChangeTime;
4094 data->LastAccessTime = 0;
4095 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004096 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004097 data->EndOfFile = data->AllocationSize;
4098 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004099 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004100 } else
4101 rc = -EIO; /* bad buffer passed in */
4102
4103 cifs_buf_release(pSMB);
4104
4105 if (rc == -EAGAIN)
4106 goto QInfRetry;
4107
4108 return rc;
4109}
4110
Jeff Laytonbcd53572010-02-12 07:44:16 -05004111int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004112CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004113 u16 netfid, FILE_ALL_INFO *pFindData)
4114{
4115 struct smb_t2_qfi_req *pSMB = NULL;
4116 struct smb_t2_qfi_rsp *pSMBr = NULL;
4117 int rc = 0;
4118 int bytes_returned;
4119 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004120
Jeff Laytonbcd53572010-02-12 07:44:16 -05004121QFileInfoRetry:
4122 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4123 (void **) &pSMBr);
4124 if (rc)
4125 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004126
Jeff Laytonbcd53572010-02-12 07:44:16 -05004127 params = 2 /* level */ + 2 /* fid */;
4128 pSMB->t2.TotalDataCount = 0;
4129 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4130 /* BB find exact max data count below from sess structure BB */
4131 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4132 pSMB->t2.MaxSetupCount = 0;
4133 pSMB->t2.Reserved = 0;
4134 pSMB->t2.Flags = 0;
4135 pSMB->t2.Timeout = 0;
4136 pSMB->t2.Reserved2 = 0;
4137 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4138 Fid) - 4);
4139 pSMB->t2.DataCount = 0;
4140 pSMB->t2.DataOffset = 0;
4141 pSMB->t2.SetupCount = 1;
4142 pSMB->t2.Reserved3 = 0;
4143 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4144 byte_count = params + 1 /* pad */ ;
4145 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4146 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4147 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4148 pSMB->Pad = 0;
4149 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004150 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004151 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004152
4153 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4154 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4155 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004156 cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004157 } else { /* decode response */
4158 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4159
4160 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4161 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004162 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004163 rc = -EIO; /* bad smb */
4164 else if (pFindData) {
4165 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4166 memcpy((char *) pFindData,
4167 (char *) &pSMBr->hdr.Protocol +
4168 data_offset, sizeof(FILE_ALL_INFO));
4169 } else
4170 rc = -ENOMEM;
4171 }
4172 cifs_buf_release(pSMB);
4173 if (rc == -EAGAIN)
4174 goto QFileInfoRetry;
4175
4176 return rc;
4177}
Steve French6b8edfe2005-08-23 20:26:03 -07004178
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004180CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004181 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004182 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004183 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004185 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 TRANSACTION2_QPI_REQ *pSMB = NULL;
4187 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4188 int rc = 0;
4189 int bytes_returned;
4190 int name_len;
4191 __u16 params, byte_count;
4192
Joe Perchesf96637b2013-05-04 22:12:25 -05004193 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194QPathInfoRetry:
4195 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4196 (void **) &pSMBr);
4197 if (rc)
4198 return rc;
4199
4200 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4201 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004202 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004203 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 name_len++; /* trailing null */
4205 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004206 } else {
4207 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 }
4209
Steve French50c2f752007-07-13 00:33:32 +00004210 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 pSMB->TotalDataCount = 0;
4212 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004213 /* BB find exact max SMB PDU from sess structure BB */
4214 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 pSMB->MaxSetupCount = 0;
4216 pSMB->Reserved = 0;
4217 pSMB->Flags = 0;
4218 pSMB->Timeout = 0;
4219 pSMB->Reserved2 = 0;
4220 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004221 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 pSMB->DataCount = 0;
4223 pSMB->DataOffset = 0;
4224 pSMB->SetupCount = 1;
4225 pSMB->Reserved3 = 0;
4226 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4227 byte_count = params + 1 /* pad */ ;
4228 pSMB->TotalParameterCount = cpu_to_le16(params);
4229 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004230 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004231 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4232 else
4233 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004235 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 pSMB->ByteCount = cpu_to_le16(byte_count);
4237
4238 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4239 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4240 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004241 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 } else { /* decode response */
4243 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4244
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004245 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4246 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004247 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004249 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004250 rc = -EIO; /* 24 or 26 expected but we do not read
4251 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004252 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004253 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004255
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004256 /*
4257 * On legacy responses we do not read the last field,
4258 * EAsize, fortunately since it varies by subdialect and
4259 * also note it differs on Set vs Get, ie two bytes or 4
4260 * bytes depending but we don't care here.
4261 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004262 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004263 size = sizeof(FILE_INFO_STANDARD);
4264 else
4265 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004266 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004267 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 } else
4269 rc = -ENOMEM;
4270 }
4271 cifs_buf_release(pSMB);
4272 if (rc == -EAGAIN)
4273 goto QPathInfoRetry;
4274
4275 return rc;
4276}
4277
4278int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004279CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004280 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4281{
4282 struct smb_t2_qfi_req *pSMB = NULL;
4283 struct smb_t2_qfi_rsp *pSMBr = NULL;
4284 int rc = 0;
4285 int bytes_returned;
4286 __u16 params, byte_count;
4287
4288UnixQFileInfoRetry:
4289 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4290 (void **) &pSMBr);
4291 if (rc)
4292 return rc;
4293
4294 params = 2 /* level */ + 2 /* fid */;
4295 pSMB->t2.TotalDataCount = 0;
4296 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4297 /* BB find exact max data count below from sess structure BB */
4298 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4299 pSMB->t2.MaxSetupCount = 0;
4300 pSMB->t2.Reserved = 0;
4301 pSMB->t2.Flags = 0;
4302 pSMB->t2.Timeout = 0;
4303 pSMB->t2.Reserved2 = 0;
4304 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4305 Fid) - 4);
4306 pSMB->t2.DataCount = 0;
4307 pSMB->t2.DataOffset = 0;
4308 pSMB->t2.SetupCount = 1;
4309 pSMB->t2.Reserved3 = 0;
4310 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4311 byte_count = params + 1 /* pad */ ;
4312 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4313 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4314 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4315 pSMB->Pad = 0;
4316 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004317 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004318 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004319
4320 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4321 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4322 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004323 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004324 } else { /* decode response */
4325 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4326
Jeff Layton820a8032011-05-04 08:05:26 -04004327 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004328 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 -05004329 rc = -EIO; /* bad smb */
4330 } else {
4331 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4332 memcpy((char *) pFindData,
4333 (char *) &pSMBr->hdr.Protocol +
4334 data_offset,
4335 sizeof(FILE_UNIX_BASIC_INFO));
4336 }
4337 }
4338
4339 cifs_buf_release(pSMB);
4340 if (rc == -EAGAIN)
4341 goto UnixQFileInfoRetry;
4342
4343 return rc;
4344}
4345
4346int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004347CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004349 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004350 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351{
4352/* SMB_QUERY_FILE_UNIX_BASIC */
4353 TRANSACTION2_QPI_REQ *pSMB = NULL;
4354 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4355 int rc = 0;
4356 int bytes_returned = 0;
4357 int name_len;
4358 __u16 params, byte_count;
4359
Joe Perchesf96637b2013-05-04 22:12:25 -05004360 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361UnixQPathInfoRetry:
4362 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4363 (void **) &pSMBr);
4364 if (rc)
4365 return rc;
4366
4367 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4368 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004369 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4370 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 name_len++; /* trailing null */
4372 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004373 } else {
4374 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 }
4376
Steve French50c2f752007-07-13 00:33:32 +00004377 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 pSMB->TotalDataCount = 0;
4379 pSMB->MaxParameterCount = cpu_to_le16(2);
4380 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004381 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 pSMB->MaxSetupCount = 0;
4383 pSMB->Reserved = 0;
4384 pSMB->Flags = 0;
4385 pSMB->Timeout = 0;
4386 pSMB->Reserved2 = 0;
4387 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004388 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 pSMB->DataCount = 0;
4390 pSMB->DataOffset = 0;
4391 pSMB->SetupCount = 1;
4392 pSMB->Reserved3 = 0;
4393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4394 byte_count = params + 1 /* pad */ ;
4395 pSMB->TotalParameterCount = cpu_to_le16(params);
4396 pSMB->ParameterCount = pSMB->TotalParameterCount;
4397 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4398 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004399 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 pSMB->ByteCount = cpu_to_le16(byte_count);
4401
4402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4404 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004405 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 } else { /* decode response */
4407 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4408
Jeff Layton820a8032011-05-04 08:05:26 -04004409 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004410 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 -07004411 rc = -EIO; /* bad smb */
4412 } else {
4413 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4414 memcpy((char *) pFindData,
4415 (char *) &pSMBr->hdr.Protocol +
4416 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004417 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 }
4419 }
4420 cifs_buf_release(pSMB);
4421 if (rc == -EAGAIN)
4422 goto UnixQPathInfoRetry;
4423
4424 return rc;
4425}
4426
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427/* xid, tcon, searchName and codepage are input parms, rest are returned */
4428int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004429CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004430 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004431 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004432 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433{
4434/* level 257 SMB_ */
4435 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4436 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004437 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 int rc = 0;
4439 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004440 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004442 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443
Joe Perchesf96637b2013-05-04 22:12:25 -05004444 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445
4446findFirstRetry:
4447 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4448 (void **) &pSMBr);
4449 if (rc)
4450 return rc;
4451
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004452 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004453 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004454
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4456 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004457 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4458 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004459 /* We can not add the asterik earlier in case
4460 it got remapped to 0xF03A as if it were part of the
4461 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 name_len *= 2;
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] = 0;
4466 pSMB->FileName[name_len+2] = '*';
4467 pSMB->FileName[name_len+3] = 0;
4468 name_len += 4; /* now the trailing null */
4469 /* null terminate just in case */
4470 pSMB->FileName[name_len] = 0;
4471 pSMB->FileName[name_len+1] = 0;
4472 name_len += 2;
4473 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004474 } else {
4475 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004476 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004477 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4478 name_len = PATH_MAX-2;
4479 /* overwrite nul byte */
4480 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4481 pSMB->FileName[name_len] = '*';
4482 pSMB->FileName[name_len+1] = 0;
4483 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 }
4486
4487 params = 12 + name_len /* includes null */ ;
4488 pSMB->TotalDataCount = 0; /* no EAs */
4489 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004490 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 pSMB->MaxSetupCount = 0;
4492 pSMB->Reserved = 0;
4493 pSMB->Flags = 0;
4494 pSMB->Timeout = 0;
4495 pSMB->Reserved2 = 0;
4496 byte_count = params + 1 /* pad */ ;
4497 pSMB->TotalParameterCount = cpu_to_le16(params);
4498 pSMB->ParameterCount = pSMB->TotalParameterCount;
4499 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004500 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4501 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 pSMB->DataCount = 0;
4503 pSMB->DataOffset = 0;
4504 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4505 pSMB->Reserved3 = 0;
4506 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4507 pSMB->SearchAttributes =
4508 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4509 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004510 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004511 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4513
4514 /* BB what should we set StorageType to? Does it matter? BB */
4515 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004516 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 pSMB->ByteCount = cpu_to_le16(byte_count);
4518
4519 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4520 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004521 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522
Steve French88274812006-03-09 22:21:45 +00004523 if (rc) {/* BB add logic to retry regular search if Unix search
4524 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004526 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004527
Steve French88274812006-03-09 22:21:45 +00004528 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529
4530 /* BB eventually could optimize out free and realloc of buf */
4531 /* for this case */
4532 if (rc == -EAGAIN)
4533 goto findFirstRetry;
4534 } else { /* decode response */
4535 /* BB remember to free buffer if error BB */
4536 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004537 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004538 unsigned int lnoff;
4539
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004541 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 else
Steve French4b18f2a2008-04-29 00:06:05 +00004543 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
4545 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
zhengbin01d1bd72019-12-25 11:30:21 +08004546 psrch_inf->smallBuf = false;
Steve French50c2f752007-07-13 00:33:32 +00004547 psrch_inf->srch_entries_start =
4548 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4551 le16_to_cpu(pSMBr->t2.ParameterOffset));
4552
Steve French790fe572007-07-07 19:25:05 +00004553 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004554 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 else
Steve French4b18f2a2008-04-29 00:06:05 +00004556 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557
Steve French50c2f752007-07-13 00:33:32 +00004558 psrch_inf->entries_in_buffer =
4559 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004560 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004562 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004563 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004564 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004565 psrch_inf->last_entry = NULL;
4566 return rc;
4567 }
4568
Steve French0752f152008-10-07 20:03:33 +00004569 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004570 lnoff;
4571
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004572 if (pnetfid)
4573 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 } else {
4575 cifs_buf_release(pSMB);
4576 }
4577 }
4578
4579 return rc;
4580}
4581
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004582int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4583 __u16 searchHandle, __u16 search_flags,
4584 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585{
4586 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4587 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004588 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 char *response_data;
4590 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004591 int bytes_returned;
4592 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 __u16 params, byte_count;
4594
Joe Perchesf96637b2013-05-04 22:12:25 -05004595 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596
Steve French4b18f2a2008-04-29 00:06:05 +00004597 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 return -ENOENT;
4599
4600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4601 (void **) &pSMBr);
4602 if (rc)
4603 return rc;
4604
Steve French50c2f752007-07-13 00:33:32 +00004605 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 byte_count = 0;
4607 pSMB->TotalDataCount = 0; /* no EAs */
4608 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004609 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 pSMB->MaxSetupCount = 0;
4611 pSMB->Reserved = 0;
4612 pSMB->Flags = 0;
4613 pSMB->Timeout = 0;
4614 pSMB->Reserved2 = 0;
4615 pSMB->ParameterOffset = cpu_to_le16(
4616 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4617 pSMB->DataCount = 0;
4618 pSMB->DataOffset = 0;
4619 pSMB->SetupCount = 1;
4620 pSMB->Reserved3 = 0;
4621 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4622 pSMB->SearchHandle = searchHandle; /* always kept as le */
4623 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004624 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4626 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004627 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628
4629 name_len = psrch_inf->resume_name_len;
4630 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004631 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4633 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004634 /* 14 byte parm len above enough for 2 byte null terminator */
4635 pSMB->ResumeFileName[name_len] = 0;
4636 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 } else {
4638 rc = -EINVAL;
4639 goto FNext2_err_exit;
4640 }
4641 byte_count = params + 1 /* pad */ ;
4642 pSMB->TotalParameterCount = cpu_to_le16(params);
4643 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004644 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004646
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4648 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004649 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 if (rc) {
4651 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004652 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004653 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004654 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004656 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 } else { /* decode response */
4658 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004659
Steve French790fe572007-07-07 19:25:05 +00004660 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004661 unsigned int lnoff;
4662
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 /* BB fixme add lock for file (srch_info) struct here */
4664 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004665 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 else
Steve French4b18f2a2008-04-29 00:06:05 +00004667 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 response_data = (char *) &pSMBr->hdr.Protocol +
4669 le16_to_cpu(pSMBr->t2.ParameterOffset);
4670 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4671 response_data = (char *)&pSMBr->hdr.Protocol +
4672 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004673 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004674 cifs_small_buf_release(
4675 psrch_inf->ntwrk_buf_start);
4676 else
4677 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 psrch_inf->srch_entries_start = response_data;
4679 psrch_inf->ntwrk_buf_start = (char *)pSMB;
zhengbin01d1bd72019-12-25 11:30:21 +08004680 psrch_inf->smallBuf = false;
Steve French790fe572007-07-07 19:25:05 +00004681 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004682 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 else
Steve French4b18f2a2008-04-29 00:06:05 +00004684 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004685 psrch_inf->entries_in_buffer =
4686 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 psrch_inf->index_of_last_entry +=
4688 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004689 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004690 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004691 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004692 psrch_inf->last_entry = NULL;
4693 return rc;
4694 } else
4695 psrch_inf->last_entry =
4696 psrch_inf->srch_entries_start + lnoff;
4697
Joe Perchesf96637b2013-05-04 22:12:25 -05004698/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4699 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700
4701 /* BB fixme add unlock here */
4702 }
4703
4704 }
4705
4706 /* BB On error, should we leave previous search buf (and count and
4707 last entry fields) intact or free the previous one? */
4708
4709 /* Note: On -EAGAIN error only caller can retry on handle based calls
4710 since file handle passed in no longer valid */
4711FNext2_err_exit:
4712 if (rc != 0)
4713 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 return rc;
4715}
4716
4717int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004718CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004719 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720{
4721 int rc = 0;
4722 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723
Joe Perchesf96637b2013-05-04 22:12:25 -05004724 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4726
4727 /* no sense returning error if session restarted
4728 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004729 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 return 0;
4731 if (rc)
4732 return rc;
4733
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 pSMB->FileID = searchHandle;
4735 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004736 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004737 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004738 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004739 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004740
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004741 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742
4743 /* Since session is dead, search handle closed on server already */
4744 if (rc == -EAGAIN)
4745 rc = 0;
4746
4747 return rc;
4748}
4749
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004751CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004752 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004753 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754{
4755 int rc = 0;
4756 TRANSACTION2_QPI_REQ *pSMB = NULL;
4757 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4758 int name_len, bytes_returned;
4759 __u16 params, byte_count;
4760
Joe Perchesf96637b2013-05-04 22:12:25 -05004761 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004762 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004763 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764
4765GetInodeNumberRetry:
4766 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004767 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 if (rc)
4769 return rc;
4770
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4772 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004773 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004774 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004775 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 name_len++; /* trailing null */
4777 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004778 } else {
4779 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 }
4781
4782 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4783 pSMB->TotalDataCount = 0;
4784 pSMB->MaxParameterCount = cpu_to_le16(2);
4785 /* BB find exact max data count below from sess structure BB */
4786 pSMB->MaxDataCount = cpu_to_le16(4000);
4787 pSMB->MaxSetupCount = 0;
4788 pSMB->Reserved = 0;
4789 pSMB->Flags = 0;
4790 pSMB->Timeout = 0;
4791 pSMB->Reserved2 = 0;
4792 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004793 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 pSMB->DataCount = 0;
4795 pSMB->DataOffset = 0;
4796 pSMB->SetupCount = 1;
4797 pSMB->Reserved3 = 0;
4798 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4799 byte_count = params + 1 /* pad */ ;
4800 pSMB->TotalParameterCount = cpu_to_le16(params);
4801 pSMB->ParameterCount = pSMB->TotalParameterCount;
4802 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4803 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004804 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 pSMB->ByteCount = cpu_to_le16(byte_count);
4806
4807 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4808 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4809 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004810 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 } else {
4812 /* decode response */
4813 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004815 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 /* If rc should we check for EOPNOSUPP and
4817 disable the srvino flag? or in caller? */
4818 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004819 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4821 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004822 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004824 if (count < 8) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004825 cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 rc = -EIO;
4827 goto GetInodeNumOut;
4828 }
4829 pfinfo = (struct file_internal_info *)
4830 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004831 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 }
4833 }
4834GetInodeNumOut:
4835 cifs_buf_release(pSMB);
4836 if (rc == -EAGAIN)
4837 goto GetInodeNumberRetry;
4838 return rc;
4839}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
4841int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004842CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004843 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004844 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004845 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846{
4847/* TRANS2_GET_DFS_REFERRAL */
4848 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4849 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 int rc = 0;
4851 int bytes_returned;
4852 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004854 *num_of_nodes = 0;
4855 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
Joe Perchesf96637b2013-05-04 22:12:25 -05004857 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004858 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004860
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004862 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 (void **) &pSMBr);
4864 if (rc)
4865 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004866
4867 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004868 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004869 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004870 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004872 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004874 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876
4877 if (ses->capabilities & CAP_UNICODE) {
4878 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4879 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004880 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004881 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004882 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 name_len++; /* trailing null */
4884 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004885 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004886 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 }
4888
Dan Carpenter65c3b202015-04-30 17:30:24 +03004889 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004890 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004891
Steve French50c2f752007-07-13 00:33:32 +00004892 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004893
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 params = 2 /* level */ + name_len /*includes null */ ;
4895 pSMB->TotalDataCount = 0;
4896 pSMB->DataCount = 0;
4897 pSMB->DataOffset = 0;
4898 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004899 /* BB find exact max SMB PDU from sess structure BB */
4900 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 pSMB->MaxSetupCount = 0;
4902 pSMB->Reserved = 0;
4903 pSMB->Flags = 0;
4904 pSMB->Timeout = 0;
4905 pSMB->Reserved2 = 0;
4906 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004907 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 pSMB->SetupCount = 1;
4909 pSMB->Reserved3 = 0;
4910 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4911 byte_count = params + 3 /* pad */ ;
4912 pSMB->ParameterCount = cpu_to_le16(params);
4913 pSMB->TotalParameterCount = pSMB->ParameterCount;
4914 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004915 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 pSMB->ByteCount = cpu_to_le16(byte_count);
4917
4918 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4919 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4920 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004921 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004922 goto GetDFSRefExit;
4923 }
4924 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004926 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004927 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004928 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004929 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004931
Joe Perchesf96637b2013-05-04 22:12:25 -05004932 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4933 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004934
4935 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004936 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4937 le16_to_cpu(pSMBr->t2.DataCount),
4938 num_of_nodes, target_nodes, nls_codepage,
4939 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004940 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004941
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004943 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944
4945 if (rc == -EAGAIN)
4946 goto getDFSRetry;
4947
4948 return rc;
4949}
4950
Steve French20962432005-09-21 22:05:57 -07004951/* Query File System Info such as free space to old servers such as Win 9x */
4952int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004953SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4954 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004955{
4956/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4957 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4958 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4959 FILE_SYSTEM_ALLOC_INFO *response_data;
4960 int rc = 0;
4961 int bytes_returned = 0;
4962 __u16 params, byte_count;
4963
Joe Perchesf96637b2013-05-04 22:12:25 -05004964 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004965oldQFSInfoRetry:
4966 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4967 (void **) &pSMBr);
4968 if (rc)
4969 return rc;
Steve French20962432005-09-21 22:05:57 -07004970
4971 params = 2; /* level */
4972 pSMB->TotalDataCount = 0;
4973 pSMB->MaxParameterCount = cpu_to_le16(2);
4974 pSMB->MaxDataCount = cpu_to_le16(1000);
4975 pSMB->MaxSetupCount = 0;
4976 pSMB->Reserved = 0;
4977 pSMB->Flags = 0;
4978 pSMB->Timeout = 0;
4979 pSMB->Reserved2 = 0;
4980 byte_count = params + 1 /* pad */ ;
4981 pSMB->TotalParameterCount = cpu_to_le16(params);
4982 pSMB->ParameterCount = pSMB->TotalParameterCount;
4983 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4984 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4985 pSMB->DataCount = 0;
4986 pSMB->DataOffset = 0;
4987 pSMB->SetupCount = 1;
4988 pSMB->Reserved3 = 0;
4989 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4990 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004991 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004992 pSMB->ByteCount = cpu_to_le16(byte_count);
4993
4994 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4996 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004997 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004998 } else { /* decode response */
4999 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5000
Jeff Layton820a8032011-05-04 08:05:26 -04005001 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005002 rc = -EIO; /* bad smb */
5003 else {
5004 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005005 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005006 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005007
Steve French50c2f752007-07-13 00:33:32 +00005008 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005009 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5010 FSData->f_bsize =
5011 le16_to_cpu(response_data->BytesPerSector) *
5012 le32_to_cpu(response_data->
5013 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005014 /*
5015 * much prefer larger but if server doesn't report
5016 * a valid size than 4K is a reasonable minimum
5017 */
5018 if (FSData->f_bsize < 512)
5019 FSData->f_bsize = 4096;
5020
Steve French20962432005-09-21 22:05:57 -07005021 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005022 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005023 FSData->f_bfree = FSData->f_bavail =
5024 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005025 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5026 (unsigned long long)FSData->f_blocks,
5027 (unsigned long long)FSData->f_bfree,
5028 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005029 }
5030 }
5031 cifs_buf_release(pSMB);
5032
5033 if (rc == -EAGAIN)
5034 goto oldQFSInfoRetry;
5035
5036 return rc;
5037}
5038
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005040CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5041 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042{
5043/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5044 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5045 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5046 FILE_SYSTEM_INFO *response_data;
5047 int rc = 0;
5048 int bytes_returned = 0;
5049 __u16 params, byte_count;
5050
Joe Perchesf96637b2013-05-04 22:12:25 -05005051 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052QFSInfoRetry:
5053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5054 (void **) &pSMBr);
5055 if (rc)
5056 return rc;
5057
5058 params = 2; /* level */
5059 pSMB->TotalDataCount = 0;
5060 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005061 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 pSMB->MaxSetupCount = 0;
5063 pSMB->Reserved = 0;
5064 pSMB->Flags = 0;
5065 pSMB->Timeout = 0;
5066 pSMB->Reserved2 = 0;
5067 byte_count = params + 1 /* pad */ ;
5068 pSMB->TotalParameterCount = cpu_to_le16(params);
5069 pSMB->ParameterCount = pSMB->TotalParameterCount;
5070 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005071 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 pSMB->DataCount = 0;
5073 pSMB->DataOffset = 0;
5074 pSMB->SetupCount = 1;
5075 pSMB->Reserved3 = 0;
5076 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5077 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005078 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 pSMB->ByteCount = cpu_to_le16(byte_count);
5080
5081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5083 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005084 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005086 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087
Jeff Layton820a8032011-05-04 08:05:26 -04005088 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 rc = -EIO; /* bad smb */
5090 else {
5091 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092
5093 response_data =
5094 (FILE_SYSTEM_INFO
5095 *) (((char *) &pSMBr->hdr.Protocol) +
5096 data_offset);
5097 FSData->f_bsize =
5098 le32_to_cpu(response_data->BytesPerSector) *
5099 le32_to_cpu(response_data->
5100 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005101 /*
5102 * much prefer larger but if server doesn't report
5103 * a valid size than 4K is a reasonable minimum
5104 */
5105 if (FSData->f_bsize < 512)
5106 FSData->f_bsize = 4096;
5107
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 FSData->f_blocks =
5109 le64_to_cpu(response_data->TotalAllocationUnits);
5110 FSData->f_bfree = FSData->f_bavail =
5111 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005112 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5113 (unsigned long long)FSData->f_blocks,
5114 (unsigned long long)FSData->f_bfree,
5115 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 }
5117 }
5118 cifs_buf_release(pSMB);
5119
5120 if (rc == -EAGAIN)
5121 goto QFSInfoRetry;
5122
5123 return rc;
5124}
5125
5126int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005127CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128{
5129/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5130 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5131 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5132 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5133 int rc = 0;
5134 int bytes_returned = 0;
5135 __u16 params, byte_count;
5136
Joe Perchesf96637b2013-05-04 22:12:25 -05005137 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138QFSAttributeRetry:
5139 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5140 (void **) &pSMBr);
5141 if (rc)
5142 return rc;
5143
5144 params = 2; /* level */
5145 pSMB->TotalDataCount = 0;
5146 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005147 /* BB find exact max SMB PDU from sess structure BB */
5148 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 pSMB->MaxSetupCount = 0;
5150 pSMB->Reserved = 0;
5151 pSMB->Flags = 0;
5152 pSMB->Timeout = 0;
5153 pSMB->Reserved2 = 0;
5154 byte_count = params + 1 /* pad */ ;
5155 pSMB->TotalParameterCount = cpu_to_le16(params);
5156 pSMB->ParameterCount = pSMB->TotalParameterCount;
5157 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005158 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 pSMB->DataCount = 0;
5160 pSMB->DataOffset = 0;
5161 pSMB->SetupCount = 1;
5162 pSMB->Reserved3 = 0;
5163 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5164 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005165 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 pSMB->ByteCount = cpu_to_le16(byte_count);
5167
5168 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5169 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5170 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005171 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 } else { /* decode response */
5173 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5174
Jeff Layton820a8032011-05-04 08:05:26 -04005175 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005176 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 rc = -EIO; /* bad smb */
5178 } else {
5179 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5180 response_data =
5181 (FILE_SYSTEM_ATTRIBUTE_INFO
5182 *) (((char *) &pSMBr->hdr.Protocol) +
5183 data_offset);
5184 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005185 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 }
5187 }
5188 cifs_buf_release(pSMB);
5189
5190 if (rc == -EAGAIN)
5191 goto QFSAttributeRetry;
5192
5193 return rc;
5194}
5195
5196int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005197CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198{
5199/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5200 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5201 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5202 FILE_SYSTEM_DEVICE_INFO *response_data;
5203 int rc = 0;
5204 int bytes_returned = 0;
5205 __u16 params, byte_count;
5206
Joe Perchesf96637b2013-05-04 22:12:25 -05005207 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208QFSDeviceRetry:
5209 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5210 (void **) &pSMBr);
5211 if (rc)
5212 return rc;
5213
5214 params = 2; /* level */
5215 pSMB->TotalDataCount = 0;
5216 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005217 /* BB find exact max SMB PDU from sess structure BB */
5218 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 pSMB->MaxSetupCount = 0;
5220 pSMB->Reserved = 0;
5221 pSMB->Flags = 0;
5222 pSMB->Timeout = 0;
5223 pSMB->Reserved2 = 0;
5224 byte_count = params + 1 /* pad */ ;
5225 pSMB->TotalParameterCount = cpu_to_le16(params);
5226 pSMB->ParameterCount = pSMB->TotalParameterCount;
5227 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005228 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229
5230 pSMB->DataCount = 0;
5231 pSMB->DataOffset = 0;
5232 pSMB->SetupCount = 1;
5233 pSMB->Reserved3 = 0;
5234 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5235 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005236 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 pSMB->ByteCount = cpu_to_le16(byte_count);
5238
5239 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5240 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5241 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005242 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 } else { /* decode response */
5244 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5245
Jeff Layton820a8032011-05-04 08:05:26 -04005246 if (rc || get_bcc(&pSMBr->hdr) <
5247 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 rc = -EIO; /* bad smb */
5249 else {
5250 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5251 response_data =
Steve French737b7582005-04-28 22:41:06 -07005252 (FILE_SYSTEM_DEVICE_INFO *)
5253 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 data_offset);
5255 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005256 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 }
5258 }
5259 cifs_buf_release(pSMB);
5260
5261 if (rc == -EAGAIN)
5262 goto QFSDeviceRetry;
5263
5264 return rc;
5265}
5266
5267int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005268CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269{
5270/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5271 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5272 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5273 FILE_SYSTEM_UNIX_INFO *response_data;
5274 int rc = 0;
5275 int bytes_returned = 0;
5276 __u16 params, byte_count;
5277
Joe Perchesf96637b2013-05-04 22:12:25 -05005278 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005280 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5281 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 if (rc)
5283 return rc;
5284
5285 params = 2; /* level */
5286 pSMB->TotalDataCount = 0;
5287 pSMB->DataCount = 0;
5288 pSMB->DataOffset = 0;
5289 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005290 /* BB find exact max SMB PDU from sess structure BB */
5291 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 pSMB->MaxSetupCount = 0;
5293 pSMB->Reserved = 0;
5294 pSMB->Flags = 0;
5295 pSMB->Timeout = 0;
5296 pSMB->Reserved2 = 0;
5297 byte_count = params + 1 /* pad */ ;
5298 pSMB->ParameterCount = cpu_to_le16(params);
5299 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005300 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5301 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 pSMB->SetupCount = 1;
5303 pSMB->Reserved3 = 0;
5304 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5305 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005306 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 pSMB->ByteCount = cpu_to_le16(byte_count);
5308
5309 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5310 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5311 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005312 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 } else { /* decode response */
5314 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5315
Jeff Layton820a8032011-05-04 08:05:26 -04005316 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 rc = -EIO; /* bad smb */
5318 } else {
5319 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5320 response_data =
5321 (FILE_SYSTEM_UNIX_INFO
5322 *) (((char *) &pSMBr->hdr.Protocol) +
5323 data_offset);
5324 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005325 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 }
5327 }
5328 cifs_buf_release(pSMB);
5329
5330 if (rc == -EAGAIN)
5331 goto QFSUnixRetry;
5332
5333
5334 return rc;
5335}
5336
Jeremy Allisonac670552005-06-22 17:26:35 -07005337int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005338CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005339{
5340/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5341 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5342 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5343 int rc = 0;
5344 int bytes_returned = 0;
5345 __u16 params, param_offset, offset, byte_count;
5346
Joe Perchesf96637b2013-05-04 22:12:25 -05005347 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005348SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005349 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005350 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5351 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005352 if (rc)
5353 return rc;
5354
5355 params = 4; /* 2 bytes zero followed by info level. */
5356 pSMB->MaxSetupCount = 0;
5357 pSMB->Reserved = 0;
5358 pSMB->Flags = 0;
5359 pSMB->Timeout = 0;
5360 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005361 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5362 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005363 offset = param_offset + params;
5364
5365 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005366 /* BB find exact max SMB PDU from sess structure BB */
5367 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005368 pSMB->SetupCount = 1;
5369 pSMB->Reserved3 = 0;
5370 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5371 byte_count = 1 /* pad */ + params + 12;
5372
5373 pSMB->DataCount = cpu_to_le16(12);
5374 pSMB->ParameterCount = cpu_to_le16(params);
5375 pSMB->TotalDataCount = pSMB->DataCount;
5376 pSMB->TotalParameterCount = pSMB->ParameterCount;
5377 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5378 pSMB->DataOffset = cpu_to_le16(offset);
5379
5380 /* Params. */
5381 pSMB->FileNum = 0;
5382 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5383
5384 /* Data. */
5385 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5386 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5387 pSMB->ClientUnixCap = cpu_to_le64(cap);
5388
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005389 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005390 pSMB->ByteCount = cpu_to_le16(byte_count);
5391
5392 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5393 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5394 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005395 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005396 } else { /* decode response */
5397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005398 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005399 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005400 }
5401 cifs_buf_release(pSMB);
5402
5403 if (rc == -EAGAIN)
5404 goto SETFSUnixRetry;
5405
5406 return rc;
5407}
5408
5409
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410
5411int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005412CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005413 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414{
5415/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5416 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5417 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5418 FILE_SYSTEM_POSIX_INFO *response_data;
5419 int rc = 0;
5420 int bytes_returned = 0;
5421 __u16 params, byte_count;
5422
Joe Perchesf96637b2013-05-04 22:12:25 -05005423 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424QFSPosixRetry:
5425 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5426 (void **) &pSMBr);
5427 if (rc)
5428 return rc;
5429
5430 params = 2; /* level */
5431 pSMB->TotalDataCount = 0;
5432 pSMB->DataCount = 0;
5433 pSMB->DataOffset = 0;
5434 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005435 /* BB find exact max SMB PDU from sess structure BB */
5436 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 pSMB->MaxSetupCount = 0;
5438 pSMB->Reserved = 0;
5439 pSMB->Flags = 0;
5440 pSMB->Timeout = 0;
5441 pSMB->Reserved2 = 0;
5442 byte_count = params + 1 /* pad */ ;
5443 pSMB->ParameterCount = cpu_to_le16(params);
5444 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005445 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5446 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 pSMB->SetupCount = 1;
5448 pSMB->Reserved3 = 0;
5449 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5450 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005451 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 pSMB->ByteCount = cpu_to_le16(byte_count);
5453
5454 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5455 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5456 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005457 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 } else { /* decode response */
5459 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5460
Jeff Layton820a8032011-05-04 08:05:26 -04005461 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 rc = -EIO; /* bad smb */
5463 } else {
5464 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5465 response_data =
5466 (FILE_SYSTEM_POSIX_INFO
5467 *) (((char *) &pSMBr->hdr.Protocol) +
5468 data_offset);
5469 FSData->f_bsize =
5470 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005471 /*
5472 * much prefer larger but if server doesn't report
5473 * a valid size than 4K is a reasonable minimum
5474 */
5475 if (FSData->f_bsize < 512)
5476 FSData->f_bsize = 4096;
5477
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 FSData->f_blocks =
5479 le64_to_cpu(response_data->TotalBlocks);
5480 FSData->f_bfree =
5481 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005482 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 FSData->f_bavail = FSData->f_bfree;
5484 } else {
5485 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005486 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 }
Steve French790fe572007-07-07 19:25:05 +00005488 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005490 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005491 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005493 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 }
5495 }
5496 cifs_buf_release(pSMB);
5497
5498 if (rc == -EAGAIN)
5499 goto QFSPosixRetry;
5500
5501 return rc;
5502}
5503
5504
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005505/*
5506 * We can not use write of zero bytes trick to set file size due to need for
5507 * large file support. Also note that this SetPathInfo is preferred to
5508 * SetFileInfo based method in next routine which is only needed to work around
5509 * a sharing violation bugin Samba which this routine can run into.
5510 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005512CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005513 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5514 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515{
5516 struct smb_com_transaction2_spi_req *pSMB = NULL;
5517 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5518 struct file_end_of_file_info *parm_data;
5519 int name_len;
5520 int rc = 0;
5521 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005522 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005523
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 __u16 params, byte_count, data_count, param_offset, offset;
5525
Joe Perchesf96637b2013-05-04 22:12:25 -05005526 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527SetEOFRetry:
5528 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5529 (void **) &pSMBr);
5530 if (rc)
5531 return rc;
5532
5533 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5534 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005535 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5536 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 name_len++; /* trailing null */
5538 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005539 } else {
5540 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 }
5542 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005543 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005545 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 pSMB->MaxSetupCount = 0;
5547 pSMB->Reserved = 0;
5548 pSMB->Flags = 0;
5549 pSMB->Timeout = 0;
5550 pSMB->Reserved2 = 0;
5551 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005552 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005554 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005555 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5556 pSMB->InformationLevel =
5557 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5558 else
5559 pSMB->InformationLevel =
5560 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5561 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5563 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005564 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 else
5566 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005567 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 }
5569
5570 parm_data =
5571 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5572 offset);
5573 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5574 pSMB->DataOffset = cpu_to_le16(offset);
5575 pSMB->SetupCount = 1;
5576 pSMB->Reserved3 = 0;
5577 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5578 byte_count = 3 /* pad */ + params + data_count;
5579 pSMB->DataCount = cpu_to_le16(data_count);
5580 pSMB->TotalDataCount = pSMB->DataCount;
5581 pSMB->ParameterCount = cpu_to_le16(params);
5582 pSMB->TotalParameterCount = pSMB->ParameterCount;
5583 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005584 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 parm_data->FileSize = cpu_to_le64(size);
5586 pSMB->ByteCount = cpu_to_le16(byte_count);
5587 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5588 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005589 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005590 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591
5592 cifs_buf_release(pSMB);
5593
5594 if (rc == -EAGAIN)
5595 goto SetEOFRetry;
5596
5597 return rc;
5598}
5599
5600int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005601CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5602 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603{
5604 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 struct file_end_of_file_info *parm_data;
5606 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 __u16 params, param_offset, offset, byte_count, count;
5608
Joe Perchesf96637b2013-05-04 22:12:25 -05005609 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5610 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005611 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5612
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 if (rc)
5614 return rc;
5615
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005616 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5617 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005618
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 params = 6;
5620 pSMB->MaxSetupCount = 0;
5621 pSMB->Reserved = 0;
5622 pSMB->Flags = 0;
5623 pSMB->Timeout = 0;
5624 pSMB->Reserved2 = 0;
5625 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5626 offset = param_offset + params;
5627
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 count = sizeof(struct file_end_of_file_info);
5629 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005630 /* BB find exact max SMB PDU from sess structure BB */
5631 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 pSMB->SetupCount = 1;
5633 pSMB->Reserved3 = 0;
5634 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5635 byte_count = 3 /* pad */ + params + count;
5636 pSMB->DataCount = cpu_to_le16(count);
5637 pSMB->ParameterCount = cpu_to_le16(params);
5638 pSMB->TotalDataCount = pSMB->DataCount;
5639 pSMB->TotalParameterCount = pSMB->ParameterCount;
5640 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5641 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005642 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5643 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 pSMB->DataOffset = cpu_to_le16(offset);
5645 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005646 pSMB->Fid = cfile->fid.netfid;
5647 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5649 pSMB->InformationLevel =
5650 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5651 else
5652 pSMB->InformationLevel =
5653 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005654 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5656 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005657 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 else
5659 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005660 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 }
5662 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005663 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005665 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005666 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005668 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5669 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 }
5671
Steve French50c2f752007-07-13 00:33:32 +00005672 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 since file handle passed in no longer valid */
5674
5675 return rc;
5676}
5677
Steve French50c2f752007-07-13 00:33:32 +00005678/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679 an open handle, rather than by pathname - this is awkward due to
5680 potential access conflicts on the open, but it is unavoidable for these
5681 old servers since the only other choice is to go from 100 nanosecond DCE
5682 time and resort to the original setpathinfo level which takes the ancient
5683 DOS time format with 2 second granularity */
5684int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005685CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005686 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687{
5688 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 char *data_offset;
5690 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 __u16 params, param_offset, offset, byte_count, count;
5692
Joe Perchesf96637b2013-05-04 22:12:25 -05005693 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005694 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5695
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 if (rc)
5697 return rc;
5698
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005699 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5700 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005701
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702 params = 6;
5703 pSMB->MaxSetupCount = 0;
5704 pSMB->Reserved = 0;
5705 pSMB->Flags = 0;
5706 pSMB->Timeout = 0;
5707 pSMB->Reserved2 = 0;
5708 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5709 offset = param_offset + params;
5710
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005711 data_offset = (char *)pSMB +
5712 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713
Steve French26f57362007-08-30 22:09:15 +00005714 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005716 /* BB find max SMB PDU from sess */
5717 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 pSMB->SetupCount = 1;
5719 pSMB->Reserved3 = 0;
5720 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5721 byte_count = 3 /* pad */ + params + count;
5722 pSMB->DataCount = cpu_to_le16(count);
5723 pSMB->ParameterCount = cpu_to_le16(params);
5724 pSMB->TotalDataCount = pSMB->DataCount;
5725 pSMB->TotalParameterCount = pSMB->ParameterCount;
5726 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5727 pSMB->DataOffset = cpu_to_le16(offset);
5728 pSMB->Fid = fid;
5729 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5730 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5731 else
5732 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5733 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005734 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005736 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005737 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005738 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005739 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005740 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5741 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742
Steve French50c2f752007-07-13 00:33:32 +00005743 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744 since file handle passed in no longer valid */
5745
5746 return rc;
5747}
5748
Jeff Layton6d22f092008-09-23 11:48:35 -04005749int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005750CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005751 bool delete_file, __u16 fid, __u32 pid_of_opener)
5752{
5753 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5754 char *data_offset;
5755 int rc = 0;
5756 __u16 params, param_offset, offset, byte_count, count;
5757
Joe Perchesf96637b2013-05-04 22:12:25 -05005758 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005759 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5760
5761 if (rc)
5762 return rc;
5763
5764 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5765 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5766
5767 params = 6;
5768 pSMB->MaxSetupCount = 0;
5769 pSMB->Reserved = 0;
5770 pSMB->Flags = 0;
5771 pSMB->Timeout = 0;
5772 pSMB->Reserved2 = 0;
5773 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5774 offset = param_offset + params;
5775
5776 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5777
5778 count = 1;
5779 pSMB->MaxParameterCount = cpu_to_le16(2);
5780 /* BB find max SMB PDU from sess */
5781 pSMB->MaxDataCount = cpu_to_le16(1000);
5782 pSMB->SetupCount = 1;
5783 pSMB->Reserved3 = 0;
5784 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5785 byte_count = 3 /* pad */ + params + count;
5786 pSMB->DataCount = cpu_to_le16(count);
5787 pSMB->ParameterCount = cpu_to_le16(params);
5788 pSMB->TotalDataCount = pSMB->DataCount;
5789 pSMB->TotalParameterCount = pSMB->ParameterCount;
5790 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5791 pSMB->DataOffset = cpu_to_le16(offset);
5792 pSMB->Fid = fid;
5793 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5794 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005795 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005796 pSMB->ByteCount = cpu_to_le16(byte_count);
5797 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005798 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005799 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005800 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005801 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005802
5803 return rc;
5804}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005806static int
5807CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
5808 const char *fileName, const FILE_BASIC_INFO *data,
5809 const struct nls_table *nls_codepage,
5810 struct cifs_sb_info *cifs_sb)
5811{
5812 int oplock = 0;
5813 struct cifs_open_parms oparms;
5814 struct cifs_fid fid;
5815 int rc;
5816
5817 oparms.tcon = tcon;
5818 oparms.cifs_sb = cifs_sb;
5819 oparms.desired_access = GENERIC_WRITE;
5820 oparms.create_options = cifs_create_options(cifs_sb, 0);
5821 oparms.disposition = FILE_OPEN;
5822 oparms.path = fileName;
5823 oparms.fid = &fid;
5824 oparms.reconnect = false;
5825
5826 rc = CIFS_open(xid, &oparms, &oplock, NULL);
5827 if (rc)
5828 goto out;
5829
5830 rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
5831 CIFSSMBClose(xid, tcon, fid.netfid);
5832out:
5833
5834 return rc;
5835}
5836
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005838CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005839 const char *fileName, const FILE_BASIC_INFO *data,
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005840 const struct nls_table *nls_codepage,
5841 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842{
5843 TRANSACTION2_SPI_REQ *pSMB = NULL;
5844 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5845 int name_len;
5846 int rc = 0;
5847 int bytes_returned = 0;
5848 char *data_offset;
5849 __u16 params, param_offset, offset, byte_count, count;
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005850 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851
Joe Perchesf96637b2013-05-04 22:12:25 -05005852 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853
5854SetTimesRetry:
5855 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5856 (void **) &pSMBr);
5857 if (rc)
5858 return rc;
5859
5860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5861 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005862 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5863 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 name_len++; /* trailing null */
5865 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005866 } else {
5867 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 }
5869
5870 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005871 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005873 /* BB find max SMB PDU from sess structure BB */
5874 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 pSMB->MaxSetupCount = 0;
5876 pSMB->Reserved = 0;
5877 pSMB->Flags = 0;
5878 pSMB->Timeout = 0;
5879 pSMB->Reserved2 = 0;
5880 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005881 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 offset = param_offset + params;
5883 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5884 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5885 pSMB->DataOffset = cpu_to_le16(offset);
5886 pSMB->SetupCount = 1;
5887 pSMB->Reserved3 = 0;
5888 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5889 byte_count = 3 /* pad */ + params + count;
5890
5891 pSMB->DataCount = cpu_to_le16(count);
5892 pSMB->ParameterCount = cpu_to_le16(params);
5893 pSMB->TotalDataCount = pSMB->DataCount;
5894 pSMB->TotalParameterCount = pSMB->ParameterCount;
5895 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5896 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5897 else
5898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5899 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005900 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005901 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 pSMB->ByteCount = cpu_to_le16(byte_count);
5903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005905 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005906 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907
5908 cifs_buf_release(pSMB);
5909
5910 if (rc == -EAGAIN)
5911 goto SetTimesRetry;
5912
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005913 if (rc == -EOPNOTSUPP)
5914 return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
5915 nls_codepage, cifs_sb);
5916
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 return rc;
5918}
5919
5920/* Can not be used to set time stamps yet (due to old DOS time format) */
5921/* Can be used to set attributes */
5922#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5923 handling it anyway and NT4 was what we thought it would be needed for
5924 Do not delete it until we prove whether needed for Win9x though */
5925int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005926CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 __u16 dos_attrs, const struct nls_table *nls_codepage)
5928{
5929 SETATTR_REQ *pSMB = NULL;
5930 SETATTR_RSP *pSMBr = NULL;
5931 int rc = 0;
5932 int bytes_returned;
5933 int name_len;
5934
Joe Perchesf96637b2013-05-04 22:12:25 -05005935 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936
5937SetAttrLgcyRetry:
5938 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5939 (void **) &pSMBr);
5940 if (rc)
5941 return rc;
5942
5943 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5944 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005945 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5946 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947 name_len++; /* trailing null */
5948 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005949 } else {
5950 name_len = copy_path_name(pSMB->fileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 }
5952 pSMB->attr = cpu_to_le16(dos_attrs);
5953 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005954 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005958 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005959 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960
5961 cifs_buf_release(pSMB);
5962
5963 if (rc == -EAGAIN)
5964 goto SetAttrLgcyRetry;
5965
5966 return rc;
5967}
5968#endif /* temporarily unneeded SetAttr legacy function */
5969
Jeff Layton654cf142009-07-09 20:02:49 -04005970static void
5971cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5972 const struct cifs_unix_set_info_args *args)
5973{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005974 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005975 u64 mode = args->mode;
5976
Eric W. Biederman49418b22013-02-06 00:57:56 -08005977 if (uid_valid(args->uid))
5978 uid = from_kuid(&init_user_ns, args->uid);
5979 if (gid_valid(args->gid))
5980 gid = from_kgid(&init_user_ns, args->gid);
5981
Jeff Layton654cf142009-07-09 20:02:49 -04005982 /*
5983 * Samba server ignores set of file size to zero due to bugs in some
5984 * older clients, but we should be precise - we use SetFileSize to
5985 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005986 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005987 * zero instead of -1 here
5988 */
5989 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5990 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5991 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5992 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5993 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005994 data_offset->Uid = cpu_to_le64(uid);
5995 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005996 /* better to leave device as zero when it is */
5997 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5998 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5999 data_offset->Permissions = cpu_to_le64(mode);
6000
6001 if (S_ISREG(mode))
6002 data_offset->Type = cpu_to_le32(UNIX_FILE);
6003 else if (S_ISDIR(mode))
6004 data_offset->Type = cpu_to_le32(UNIX_DIR);
6005 else if (S_ISLNK(mode))
6006 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6007 else if (S_ISCHR(mode))
6008 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6009 else if (S_ISBLK(mode))
6010 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6011 else if (S_ISFIFO(mode))
6012 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6013 else if (S_ISSOCK(mode))
6014 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6015}
6016
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006018CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006019 const struct cifs_unix_set_info_args *args,
6020 u16 fid, u32 pid_of_opener)
6021{
6022 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006023 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006024 int rc = 0;
6025 u16 params, param_offset, offset, byte_count, count;
6026
Joe Perchesf96637b2013-05-04 22:12:25 -05006027 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006028 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6029
6030 if (rc)
6031 return rc;
6032
6033 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6034 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6035
6036 params = 6;
6037 pSMB->MaxSetupCount = 0;
6038 pSMB->Reserved = 0;
6039 pSMB->Flags = 0;
6040 pSMB->Timeout = 0;
6041 pSMB->Reserved2 = 0;
6042 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6043 offset = param_offset + params;
6044
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006045 data_offset = (char *)pSMB +
6046 offsetof(struct smb_hdr, Protocol) + offset;
6047
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006048 count = sizeof(FILE_UNIX_BASIC_INFO);
6049
6050 pSMB->MaxParameterCount = cpu_to_le16(2);
6051 /* BB find max SMB PDU from sess */
6052 pSMB->MaxDataCount = cpu_to_le16(1000);
6053 pSMB->SetupCount = 1;
6054 pSMB->Reserved3 = 0;
6055 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6056 byte_count = 3 /* pad */ + params + count;
6057 pSMB->DataCount = cpu_to_le16(count);
6058 pSMB->ParameterCount = cpu_to_le16(params);
6059 pSMB->TotalDataCount = pSMB->DataCount;
6060 pSMB->TotalParameterCount = pSMB->ParameterCount;
6061 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6062 pSMB->DataOffset = cpu_to_le16(offset);
6063 pSMB->Fid = fid;
6064 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6065 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006066 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006067 pSMB->ByteCount = cpu_to_le16(byte_count);
6068
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006069 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006070
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006071 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006072 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006073 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006074 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6075 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006076
6077 /* Note: On -EAGAIN error only caller can retry on handle based calls
6078 since file handle passed in no longer valid */
6079
6080 return rc;
6081}
6082
6083int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006084CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006085 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006086 const struct cifs_unix_set_info_args *args,
6087 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088{
6089 TRANSACTION2_SPI_REQ *pSMB = NULL;
6090 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6091 int name_len;
6092 int rc = 0;
6093 int bytes_returned = 0;
6094 FILE_UNIX_BASIC_INFO *data_offset;
6095 __u16 params, param_offset, offset, count, byte_count;
6096
Joe Perchesf96637b2013-05-04 22:12:25 -05006097 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098setPermsRetry:
6099 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6100 (void **) &pSMBr);
6101 if (rc)
6102 return rc;
6103
6104 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6105 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006106 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006107 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 name_len++; /* trailing null */
6109 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006110 } else {
6111 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 }
6113
6114 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006115 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006117 /* BB find max SMB PDU from sess structure BB */
6118 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 pSMB->MaxSetupCount = 0;
6120 pSMB->Reserved = 0;
6121 pSMB->Flags = 0;
6122 pSMB->Timeout = 0;
6123 pSMB->Reserved2 = 0;
6124 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006125 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126 offset = param_offset + params;
6127 data_offset =
6128 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6129 offset);
6130 memset(data_offset, 0, count);
6131 pSMB->DataOffset = cpu_to_le16(offset);
6132 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6133 pSMB->SetupCount = 1;
6134 pSMB->Reserved3 = 0;
6135 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6136 byte_count = 3 /* pad */ + params + count;
6137 pSMB->ParameterCount = cpu_to_le16(params);
6138 pSMB->DataCount = cpu_to_le16(count);
6139 pSMB->TotalParameterCount = pSMB->ParameterCount;
6140 pSMB->TotalDataCount = pSMB->DataCount;
6141 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6142 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006143 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006144
Jeff Layton654cf142009-07-09 20:02:49 -04006145 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146
6147 pSMB->ByteCount = cpu_to_le16(byte_count);
6148 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6149 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006150 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006151 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152
Steve French0d817bc2008-05-22 02:02:03 +00006153 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154 if (rc == -EAGAIN)
6155 goto setPermsRetry;
6156 return rc;
6157}
6158
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006160/*
6161 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6162 * function used by listxattr and getxattr type calls. When ea_name is set,
6163 * it looks for that attribute name and stuffs that value into the EAData
6164 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6165 * buffer. In both cases, the return value is either the length of the
6166 * resulting data or a negative error code. If EAData is a NULL pointer then
6167 * the data isn't copied to it, but the length is returned.
6168 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006169ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006170CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006171 const unsigned char *searchName, const unsigned char *ea_name,
6172 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006173 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174{
6175 /* BB assumes one setup word */
6176 TRANSACTION2_QPI_REQ *pSMB = NULL;
6177 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006178 int remap = cifs_remap(cifs_sb);
6179 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180 int rc = 0;
6181 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006182 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006183 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006184 struct fea *temp_fea;
6185 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006186 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006187 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006188 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189
Joe Perchesf96637b2013-05-04 22:12:25 -05006190 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191QAllEAsRetry:
6192 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6193 (void **) &pSMBr);
6194 if (rc)
6195 return rc;
6196
6197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006198 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006199 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6200 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006201 list_len++; /* trailing null */
6202 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006203 } else {
6204 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205 }
6206
Jeff Layton6e462b92010-02-10 16:18:26 -05006207 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208 pSMB->TotalDataCount = 0;
6209 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006210 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006211 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 pSMB->MaxSetupCount = 0;
6213 pSMB->Reserved = 0;
6214 pSMB->Flags = 0;
6215 pSMB->Timeout = 0;
6216 pSMB->Reserved2 = 0;
6217 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006218 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 pSMB->DataCount = 0;
6220 pSMB->DataOffset = 0;
6221 pSMB->SetupCount = 1;
6222 pSMB->Reserved3 = 0;
6223 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6224 byte_count = params + 1 /* pad */ ;
6225 pSMB->TotalParameterCount = cpu_to_le16(params);
6226 pSMB->ParameterCount = pSMB->TotalParameterCount;
6227 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6228 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006229 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230 pSMB->ByteCount = cpu_to_le16(byte_count);
6231
6232 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6233 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6234 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006235 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006236 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006238
6239
6240 /* BB also check enough total bytes returned */
6241 /* BB we need to improve the validity checking
6242 of these trans2 responses */
6243
6244 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006245 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006246 rc = -EIO; /* bad smb */
6247 goto QAllEAsOut;
6248 }
6249
6250 /* check that length of list is not more than bcc */
6251 /* check that each entry does not go beyond length
6252 of list */
6253 /* check that each element of each entry does not
6254 go beyond end of list */
6255 /* validate_trans2_offsets() */
6256 /* BB check if start of smb + data_offset > &bcc+ bcc */
6257
6258 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6259 ea_response_data = (struct fealist *)
6260 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6261
Jeff Layton6e462b92010-02-10 16:18:26 -05006262 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006263 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006264 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006265 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006266 /* didn't find the named attribute */
6267 if (ea_name)
6268 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006269 goto QAllEAsOut;
6270 }
6271
Jeff Layton0cd126b2010-02-10 16:18:26 -05006272 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006273 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006274 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006275 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006276 rc = -EIO;
6277 goto QAllEAsOut;
6278 }
6279
Jeff Laytonf0d38682010-02-10 16:18:26 -05006280 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006281 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006282 temp_fea = ea_response_data->list;
6283 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006284 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006285 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006286 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006287
Jeff Layton6e462b92010-02-10 16:18:26 -05006288 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006289 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006290 /* make sure we can read name_len and value_len */
6291 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006292 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006293 rc = -EIO;
6294 goto QAllEAsOut;
6295 }
6296
6297 name_len = temp_fea->name_len;
6298 value_len = le16_to_cpu(temp_fea->value_len);
6299 list_len -= name_len + 1 + value_len;
6300 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006301 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006302 rc = -EIO;
6303 goto QAllEAsOut;
6304 }
6305
Jeff Layton31c05192010-02-10 16:18:26 -05006306 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006307 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006308 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006309 temp_ptr += name_len + 1;
6310 rc = value_len;
6311 if (buf_size == 0)
6312 goto QAllEAsOut;
6313 if ((size_t)value_len > buf_size) {
6314 rc = -ERANGE;
6315 goto QAllEAsOut;
6316 }
6317 memcpy(EAData, temp_ptr, value_len);
6318 goto QAllEAsOut;
6319 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006320 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006321 /* account for prefix user. and trailing null */
6322 rc += (5 + 1 + name_len);
6323 if (rc < (int) buf_size) {
6324 memcpy(EAData, "user.", 5);
6325 EAData += 5;
6326 memcpy(EAData, temp_ptr, name_len);
6327 EAData += name_len;
6328 /* null terminate name */
6329 *EAData = 0;
6330 ++EAData;
6331 } else if (buf_size == 0) {
6332 /* skip copy - calc size only */
6333 } else {
6334 /* stop before overrun buffer */
6335 rc = -ERANGE;
6336 break;
6337 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006338 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006339 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006340 temp_fea = (struct fea *)temp_ptr;
6341 }
6342
Jeff Layton31c05192010-02-10 16:18:26 -05006343 /* didn't find the named attribute */
6344 if (ea_name)
6345 rc = -ENODATA;
6346
Jeff Laytonf0d38682010-02-10 16:18:26 -05006347QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006348 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 if (rc == -EAGAIN)
6350 goto QAllEAsRetry;
6351
6352 return (ssize_t)rc;
6353}
6354
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006356CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6357 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006358 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006359 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360{
6361 struct smb_com_transaction2_spi_req *pSMB = NULL;
6362 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6363 struct fealist *parm_data;
6364 int name_len;
6365 int rc = 0;
6366 int bytes_returned = 0;
6367 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006368 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369
Joe Perchesf96637b2013-05-04 22:12:25 -05006370 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006371SetEARetry:
6372 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6373 (void **) &pSMBr);
6374 if (rc)
6375 return rc;
6376
6377 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6378 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006379 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6380 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381 name_len++; /* trailing null */
6382 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006383 } else {
6384 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385 }
6386
6387 params = 6 + name_len;
6388
6389 /* done calculating parms using name_len of file name,
6390 now use name_len to calculate length of ea name
6391 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006392 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 name_len = 0;
6394 else
Steve French50c2f752007-07-13 00:33:32 +00006395 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006396
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006397 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006399 /* BB find max SMB PDU from sess */
6400 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401 pSMB->MaxSetupCount = 0;
6402 pSMB->Reserved = 0;
6403 pSMB->Flags = 0;
6404 pSMB->Timeout = 0;
6405 pSMB->Reserved2 = 0;
6406 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006407 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 offset = param_offset + params;
6409 pSMB->InformationLevel =
6410 cpu_to_le16(SMB_SET_FILE_EA);
6411
Arnd Bergmannade7db92018-02-02 16:48:47 +01006412 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6414 pSMB->DataOffset = cpu_to_le16(offset);
6415 pSMB->SetupCount = 1;
6416 pSMB->Reserved3 = 0;
6417 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6418 byte_count = 3 /* pad */ + params + count;
6419 pSMB->DataCount = cpu_to_le16(count);
6420 parm_data->list_len = cpu_to_le32(count);
6421 parm_data->list[0].EA_flags = 0;
6422 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006423 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006425 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006426 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427 parm_data->list[0].name[name_len] = 0;
6428 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6429 /* caller ensures that ea_value_len is less than 64K but
6430 we need to ensure that it fits within the smb */
6431
Steve French50c2f752007-07-13 00:33:32 +00006432 /*BB add length check to see if it would fit in
6433 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006434 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6435 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006436 memcpy(parm_data->list[0].name+name_len+1,
6437 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438
6439 pSMB->TotalDataCount = pSMB->DataCount;
6440 pSMB->ParameterCount = cpu_to_le16(params);
6441 pSMB->TotalParameterCount = pSMB->ParameterCount;
6442 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006443 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444 pSMB->ByteCount = cpu_to_le16(byte_count);
6445 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6446 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006447 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006448 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
6450 cifs_buf_release(pSMB);
6451
6452 if (rc == -EAGAIN)
6453 goto SetEARetry;
6454
6455 return rc;
6456}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457#endif