blob: 243d17696f06199d5488b97bfdccdea218838ccc [file] [log] [blame]
Steve French929be902021-06-18 00:31:49 -05001// SPDX-License-Identifier: LGPL-2.1
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
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 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
12 /* These are mostly routines that operate on a pathname, or on a tree id */
13 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000014 /* treated slightly differently for reconnection purposes since we never */
15 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17#include <linux/fs.h>
18#include <linux/kernel.h>
19#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040022#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040023#include <linux/swap.h>
24#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080025#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "cifspdu.h"
27#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000028#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "cifsproto.h"
30#include "cifs_unicode.h"
31#include "cifs_debug.h"
Pavel Shilovskyd9191312019-12-10 11:44:52 -080032#include "smb2proto.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040033#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070034#include "smbdirect.h"
Paulo Alcantara08744012018-11-14 17:24:29 -020035#ifdef CONFIG_CIFS_DFS_UPCALL
36#include "dfs_cache.h"
37#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39#ifdef CONFIG_CIFS_POSIX
40static struct {
41 int index;
42 char *name;
43} protocols[] = {
Steve French50c2f752007-07-13 00:33:32 +000044 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000045 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 {BAD_PROT, "\2"}
47};
48#else
49static struct {
50 int index;
51 char *name;
52} protocols[] = {
Steve French790fe572007-07-07 19:25:05 +000053 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 {BAD_PROT, "\2"}
55};
56#endif
57
Steve French39798772006-05-31 22:40:51 +000058/* define the number of elements in the cifs dialect array */
59#ifdef CONFIG_CIFS_POSIX
Steve French39798772006-05-31 22:40:51 +000060#define CIFS_NUM_PROT 2
Steve French39798772006-05-31 22:40:51 +000061#else /* not posix */
Steve French39798772006-05-31 22:40:51 +000062#define CIFS_NUM_PROT 1
Steve French39798772006-05-31 22:40:51 +000063#endif /* CIFS_POSIX */
64
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040065/*
66 * Mark as invalid, all open files on tree connections since they
67 * were closed when session to server was lost.
68 */
69void
70cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
72 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000073 struct list_head *tmp;
74 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040076 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -050077 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040078 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000079 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000080 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040081 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 }
Steve French3afca262016-09-22 18:58:16 -050083 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -050084
Ronnie Sahlberga93864d2018-06-14 06:48:35 +100085 mutex_lock(&tcon->crfid.fid_mutex);
86 tcon->crfid.is_valid = false;
Pavel Shilovskyd9191312019-12-10 11:44:52 -080087 /* cached handle is not valid, so SMB2_CLOSE won't be sent below */
Ronnie Sahlberg45c0f1a2021-03-09 09:07:29 +100088 close_cached_dir_lease_locked(&tcon->crfid);
Ronnie Sahlberga93864d2018-06-14 06:48:35 +100089 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
90 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -050091
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040092 /*
93 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
94 * to this tcon.
95 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
97
Jeff Layton9162ab22009-09-03 12:07:17 -040098/* reconnect the socket, tcon, and smb session if needed */
99static int
Steve French96daf2b2011-05-27 04:34:02 +0000100cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400101{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400102 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000103 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400104 struct TCP_Server_Info *server;
105 struct nls_table *nls_codepage;
Paulo Alcantara08744012018-11-14 17:24:29 -0200106 int retries;
Jeff Layton9162ab22009-09-03 12:07:17 -0400107
108 /*
109 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
110 * tcp and smb session status done differently for those three - in the
111 * calling routine
112 */
113 if (!tcon)
114 return 0;
115
116 ses = tcon->ses;
117 server = ses->server;
118
119 /*
120 * only tree disconnect, open, and write, (and ulogoff which does not
121 * have tcon) are allowed as we start force umount
122 */
123 if (tcon->tidStatus == CifsExiting) {
124 if (smb_command != SMB_COM_WRITE_ANDX &&
125 smb_command != SMB_COM_OPEN_ANDX &&
126 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500127 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
128 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400129 return -ENODEV;
130 }
131 }
132
Paulo Alcantara08744012018-11-14 17:24:29 -0200133 retries = server->nr_targets;
134
Jeff Layton9162ab22009-09-03 12:07:17 -0400135 /*
Paulo Alcantara08744012018-11-14 17:24:29 -0200136 * Give demultiplex thread up to 10 seconds to each target available for
137 * reconnect -- should be greater than cifs socket timeout which is 7
138 * seconds.
Jeff Layton9162ab22009-09-03 12:07:17 -0400139 */
140 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300141 rc = wait_event_interruptible_timeout(server->response_q,
142 (server->tcpStatus != CifsNeedReconnect),
143 10 * HZ);
144 if (rc < 0) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700145 cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
146 __func__);
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300147 return -ERESTARTSYS;
148 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400149
Steve Frenchfd88ce92011-04-12 01:01:14 +0000150 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400151 if (server->tcpStatus != CifsNeedReconnect)
152 break;
153
Ronnie Sahlberg09c40b12020-02-06 13:55:19 +1000154 if (retries && --retries)
Paulo Alcantara08744012018-11-14 17:24:29 -0200155 continue;
156
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 /*
158 * on "soft" mounts we wait once. Hard mounts keep
159 * retrying until process is killed or server comes
160 * back on-line
161 */
Jeff Laytond4025392011-02-07 08:54:35 -0500162 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500163 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400164 return -EHOSTDOWN;
165 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200166 retries = server->nr_targets;
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 }
168
169 if (!ses->need_reconnect && !tcon->need_reconnect)
170 return 0;
171
172 nls_codepage = load_nls_default();
173
174 /*
175 * need to prevent multiple threads trying to simultaneously
176 * reconnect the same SMB session
177 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000178 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200179
180 /*
181 * Recheck after acquire mutex. If another thread is negotiating
182 * and the server never sends an answer the socket will be closed
183 * and tcpStatus set to reconnect.
184 */
185 if (server->tcpStatus == CifsNeedReconnect) {
186 rc = -EHOSTDOWN;
187 mutex_unlock(&ses->session_mutex);
188 goto out;
189 }
190
Jeff Layton198b5682010-04-24 07:57:48 -0400191 rc = cifs_negotiate_protocol(0, ses);
192 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400193 rc = cifs_setup_session(0, ses, nls_codepage);
194
195 /* do we need to reconnect tcon? */
196 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000197 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400198 goto out;
199 }
200
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400201 cifs_mark_open_files_invalid(tcon);
Stefan Metzmacher565674d2020-07-21 09:36:38 -0300202 rc = cifs_tree_connect(0, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000203 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500204 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400205
Steve Frenchc318e6c2018-04-04 14:08:52 -0500206 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700207 pr_warn_once("reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400208 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500209 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400210
Jeff Layton9162ab22009-09-03 12:07:17 -0400211 atomic_inc(&tconInfoReconnectCount);
212
213 /* tell server Unix caps we support */
Stefan Metzmacher864138c2020-02-24 14:15:00 +0100214 if (cap_unix(ses))
Jeff Layton9162ab22009-09-03 12:07:17 -0400215 reset_cifs_unix_caps(0, tcon, NULL, NULL);
216
217 /*
218 * Removed call to reopen open files here. It is safer (and faster) to
219 * reopen files one at a time as needed in read and write.
220 *
221 * FIXME: what about file locks? don't we need to reclaim them ASAP?
222 */
223
224out:
225 /*
226 * Check if handle based operation so we know whether we can continue
227 * or not without returning to caller to reset file handle
228 */
229 switch (smb_command) {
230 case SMB_COM_READ_ANDX:
231 case SMB_COM_WRITE_ANDX:
232 case SMB_COM_CLOSE:
233 case SMB_COM_FIND_CLOSE2:
234 case SMB_COM_LOCKING_ANDX:
235 rc = -EAGAIN;
236 }
237
238 unload_nls(nls_codepage);
239 return rc;
240}
241
Steve Frenchad7a2922008-02-07 23:25:02 +0000242/* Allocate and return pointer to an SMB request buffer, and set basic
243 SMB information in the SMB header. If the return code is zero, this
244 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245static int
Steve French96daf2b2011-05-27 04:34:02 +0000246small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000247 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
Jeff Laytonf5695992010-09-29 15:27:08 -0400249 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Jeff Layton9162ab22009-09-03 12:07:17 -0400251 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000252 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return rc;
254
255 *request_buf = cifs_small_buf_get();
256 if (*request_buf == NULL) {
257 /* BB should we add a retry in here if not a writepage? */
258 return -ENOMEM;
259 }
260
Steve French63135e02007-07-17 17:34:02 +0000261 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000262 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Steve French790fe572007-07-07 19:25:05 +0000264 if (tcon != NULL)
265 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700266
Jeff Laytonf5695992010-09-29 15:27:08 -0400267 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000268}
269
Steve French12b3b8f2006-02-09 21:12:47 +0000270int
Steve French50c2f752007-07-13 00:33:32 +0000271small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000272 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000273{
274 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000275 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000276
Steve French5815449d2006-02-14 01:36:20 +0000277 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000278 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000279 return rc;
280
Steve French04fdabe2006-02-10 05:52:50 +0000281 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400282 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000283 if (ses->capabilities & CAP_UNICODE)
284 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000285 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000286 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
287
288 /* uid, tid can stay at zero as set in header assemble */
289
Steve French50c2f752007-07-13 00:33:32 +0000290 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000291 this function is used after 1st of session setup requests */
292
293 return rc;
294}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296/* If the return code is zero, this function must fill in request_buf pointer */
297static int
Steve French96daf2b2011-05-27 04:34:02 +0000298__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400299 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 *request_buf = cifs_buf_get();
302 if (*request_buf == NULL) {
303 /* BB should we add a retry in here if not a writepage? */
304 return -ENOMEM;
305 }
306 /* Although the original thought was we needed the response buf for */
307 /* potential retries of smb operations it turns out we can determine */
308 /* from the mid flags when the request buffer can be resent without */
309 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000310 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000311 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000314 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Steve French790fe572007-07-07 19:25:05 +0000316 if (tcon != NULL)
317 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700318
Jeff Laytonf5695992010-09-29 15:27:08 -0400319 return 0;
320}
321
322/* If the return code is zero, this function must fill in request_buf pointer */
323static int
Steve French96daf2b2011-05-27 04:34:02 +0000324smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400325 void **request_buf, void **response_buf)
326{
327 int rc;
328
329 rc = cifs_reconnect_tcon(tcon, smb_command);
330 if (rc)
331 return rc;
332
333 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
334}
335
336static int
Steve French96daf2b2011-05-27 04:34:02 +0000337smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400338 void **request_buf, void **response_buf)
339{
340 if (tcon->ses->need_reconnect || tcon->need_reconnect)
341 return -EHOSTDOWN;
342
343 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344}
345
Steve French50c2f752007-07-13 00:33:32 +0000346static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Jeff Layton12df83c2011-01-20 13:36:51 -0500348 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Jeff Layton12df83c2011-01-20 13:36:51 -0500350 /* check for plausible wct */
351 if (pSMB->hdr.WordCount < 10)
352 goto vt2_err;
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500355 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
356 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
357 goto vt2_err;
358
Jeff Layton12df83c2011-01-20 13:36:51 -0500359 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
360 if (total_size >= 512)
361 goto vt2_err;
362
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400363 /* check that bcc is at least as big as parms + data, and that it is
364 * less than negotiated smb buffer
365 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500366 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
367 if (total_size > get_bcc(&pSMB->hdr) ||
368 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
369 goto vt2_err;
370
371 return 0;
372vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000373 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500375 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
Jeff Layton690c5222011-01-20 13:36:51 -0500377
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400378static int
Jeff Layton3f618222013-06-12 19:52:14 -0500379decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400380{
381 int rc = 0;
382 u16 count;
383 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500384 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400385
386 count = get_bcc(&pSMBr->hdr);
387 if (count < SMB1_CLIENT_GUID_SIZE)
388 return -EIO;
389
390 spin_lock(&cifs_tcp_ses_lock);
391 if (server->srv_count > 1) {
392 spin_unlock(&cifs_tcp_ses_lock);
393 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
394 cifs_dbg(FYI, "server UID changed\n");
395 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
396 }
397 } else {
398 spin_unlock(&cifs_tcp_ses_lock);
399 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
400 }
401
402 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500403 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400404 } else {
405 count -= SMB1_CLIENT_GUID_SIZE;
406 rc = decode_negTokenInit(
407 pSMBr->u.extended_response.SecurityBlob, count, server);
408 if (rc != 1)
409 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400410 }
411
412 return 0;
413}
414
Jeff Layton9ddec562013-05-26 07:00:58 -0400415int
Jeff Layton38d77c52013-05-26 07:01:00 -0400416cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400417{
Jeff Layton502858822013-06-27 12:45:00 -0400418 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
419 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400420 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
421
422 /*
423 * Is signing required by mnt options? If not then check
424 * global_secflags to see if it is there.
425 */
426 if (!mnt_sign_required)
427 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
428 CIFSSEC_MUST_SIGN);
429
430 /*
431 * If signing is required then it's automatically enabled too,
432 * otherwise, check to see if the secflags allow it.
433 */
434 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
435 (global_secflags & CIFSSEC_MAY_SIGN);
436
437 /* If server requires signing, does client allow it? */
438 if (srv_sign_required) {
439 if (!mnt_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700440 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400441 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400442 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400443 server->sign = true;
444 }
445
446 /* If client requires signing, does server allow it? */
447 if (mnt_sign_required) {
448 if (!srv_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700449 cifs_dbg(VFS, "Server does not support signing!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400450 return -ENOTSUPP;
451 }
452 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400453 }
454
Long Libb4c0412018-04-17 12:17:08 -0700455 if (cifs_rdma_enabled(server) && server->sign)
Joe Perchesa0a30362020-04-14 22:42:53 -0700456 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");
Long Libb4c0412018-04-17 12:17:08 -0700457
Jeff Layton9ddec562013-05-26 07:00:58 -0400458 return 0;
459}
460
Jeff Layton91934002013-05-26 07:00:58 -0400461static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500462should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400463{
Jeff Layton3f618222013-06-12 19:52:14 -0500464 switch (sectype) {
465 case RawNTLMSSP:
466 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400467 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500468 case Unspecified:
469 if (global_secflags &
470 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
471 return true;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500472 fallthrough;
Jeff Layton3f618222013-06-12 19:52:14 -0500473 default:
474 return false;
475 }
Jeff Layton91934002013-05-26 07:00:58 -0400476}
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400479CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
481 NEGOTIATE_REQ *pSMB;
482 NEGOTIATE_RSP *pSMBr;
483 int rc = 0;
484 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000485 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400486 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 u16 count;
488
Jeff Layton3534b852013-05-24 07:41:01 -0400489 if (!server) {
490 WARN(1, "%s: server is NULL!\n", __func__);
491 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
Jeff Layton3534b852013-05-24 07:41:01 -0400493
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
495 (void **) &pSMB, (void **) &pSMBr);
496 if (rc)
497 return rc;
Steve French750d1152006-06-27 06:28:30 +0000498
Pavel Shilovsky88257362012-05-23 14:01:59 +0400499 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000500 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000501
Jeff Layton3f618222013-06-12 19:52:14 -0500502 if (should_set_ext_sec_flag(ses->sectype)) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700503 cifs_dbg(FYI, "Requesting extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000504 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
505 }
Steve French50c2f752007-07-13 00:33:32 +0000506
Steve French39798772006-05-31 22:40:51 +0000507 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000508 /*
509 * We know that all the name entries in the protocols array
510 * are short (< 16 bytes anyway) and are NUL terminated.
511 */
Steve French50c2f752007-07-13 00:33:32 +0000512 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000513 size_t len = strlen(protocols[i].name) + 1;
514
515 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
516 count += len;
Steve French39798772006-05-31 22:40:51 +0000517 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000518 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 pSMB->ByteCount = cpu_to_le16(count);
520
521 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
522 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000523 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000524 goto neg_err_exit;
525
Jeff Layton9bf67e52010-04-24 07:57:46 -0400526 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500527 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000528 /* Check wct = 1 error case */
Ronnie Sahlberg76a3c922021-08-19 20:34:58 +1000529 if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000530 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000531 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000532 could not negotiate a common dialect */
533 rc = -EOPNOTSUPP;
534 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000535 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000536 /* unknown wct */
537 rc = -EOPNOTSUPP;
538 goto neg_err_exit;
539 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400540 /* else wct == 17, NTLM or better */
541
Steve French96daf2b2011-05-27 04:34:02 +0000542 server->sec_mode = pSMBr->SecurityMode;
543 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500544 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000545
Steve French254e55e2006-06-04 05:53:15 +0000546 /* one byte, so no need to convert this or EncryptionKeyLen from
547 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300548 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
549 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400550 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000551 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400552 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800553 /* set up max_read for readpages check */
554 server->max_read = server->maxBuf;
Steve Frencheca6acf2009-02-20 05:43:09 +0000555 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500556 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000557 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000558 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
559 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400560
Jeff Laytone598d1d82013-05-26 07:00:59 -0400561 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
562 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500563 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000564 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100565 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
566 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400567 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500568 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400569 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000570 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400571 } else {
572 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000573 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400574 }
Steve French254e55e2006-06-04 05:53:15 +0000575
Jeff Layton9ddec562013-05-26 07:00:58 -0400576 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400577 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000578neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700579 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000580
Joe Perchesf96637b2013-05-04 22:12:25 -0500581 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return rc;
583}
584
585int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400586CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
588 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Joe Perchesf96637b2013-05-04 22:12:25 -0500591 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500592
593 /* BB: do we need to check this? These should never be NULL. */
594 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
595 return -EIO;
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500598 * No need to return error on this operation if tid invalidated and
599 * closed on server already e.g. due to tcp session crashing. Also,
600 * the tcon is no longer on the list, so no need to take lock before
601 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 */
Steve French268875b2009-06-25 00:29:21 +0000603 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000604 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Steve French50c2f752007-07-13 00:33:32 +0000606 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700607 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500608 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return rc;
Steve French133672e2007-11-13 22:41:37 +0000610
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400611 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700612 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500614 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Steve French50c2f752007-07-13 00:33:32 +0000616 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500617 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (rc == -EAGAIN)
619 rc = 0;
620
621 return rc;
622}
623
Jeff Layton766fdbb2011-01-11 07:24:21 -0500624/*
625 * This is a no-op for now. We're not really interested in the reply, but
626 * rather in the fact that the server sent one and that server->lstrp
627 * gets updated.
628 *
629 * FIXME: maybe we should consider checking that the reply matches request?
630 */
631static void
632cifs_echo_callback(struct mid_q_entry *mid)
633{
634 struct TCP_Server_Info *server = mid->callback_data;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800635 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500636
637 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800638 add_credits(server, &credits, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500639}
640
641int
642CIFSSMBEcho(struct TCP_Server_Info *server)
643{
644 ECHO_REQ *smb;
645 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800646 struct kvec iov[2];
647 struct smb_rqst rqst = { .rq_iov = iov,
648 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500649
Joe Perchesf96637b2013-05-04 22:12:25 -0500650 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500651
652 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
653 if (rc)
654 return rc;
655
Steve French26c9cb62017-05-02 13:35:20 -0500656 if (server->capabilities & CAP_UNICODE)
657 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
658
Jeff Layton766fdbb2011-01-11 07:24:21 -0500659 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000660 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500661 smb->hdr.WordCount = 1;
662 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400663 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500664 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000665 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800666
667 iov[0].iov_len = 4;
668 iov[0].iov_base = smb;
669 iov[1].iov_len = get_rfc1002_length(smb);
670 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500671
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800672 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +1000673 server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500674 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500675 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500676
677 cifs_small_buf_release(smb);
678
679 return rc;
680}
681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400683CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 LOGOFF_ANDX_REQ *pSMB;
686 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Joe Perchesf96637b2013-05-04 22:12:25 -0500688 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500689
690 /*
691 * BB: do we need to check validity of ses and server? They should
692 * always be valid since we have an active reference. If not, that
693 * should probably be a BUG()
694 */
695 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return -EIO;
697
Steve Frenchd7b619c2010-02-25 05:36:46 +0000698 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000699 if (ses->need_reconnect)
700 goto session_already_dead; /* no need to send SMBlogoff if uid
701 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
703 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000704 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return rc;
706 }
707
Pavel Shilovsky88257362012-05-23 14:01:59 +0400708 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700709
Jeff Layton38d77c52013-05-26 07:01:00 -0400710 if (ses->server->sign)
711 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
713 pSMB->hdr.Uid = ses->Suid;
714
715 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400716 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700717 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000718session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000719 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000722 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 error */
724 if (rc == -EAGAIN)
725 rc = 0;
726 return rc;
727}
728
729int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400730CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
731 const char *fileName, __u16 type,
732 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000733{
734 TRANSACTION2_SPI_REQ *pSMB = NULL;
735 TRANSACTION2_SPI_RSP *pSMBr = NULL;
736 struct unlink_psx_rq *pRqD;
737 int name_len;
738 int rc = 0;
739 int bytes_returned = 0;
740 __u16 params, param_offset, offset, byte_count;
741
Joe Perchesf96637b2013-05-04 22:12:25 -0500742 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000743PsxDelete:
744 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
745 (void **) &pSMBr);
746 if (rc)
747 return rc;
748
749 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
750 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600751 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
752 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000753 name_len++; /* trailing null */
754 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000755 } else {
756 name_len = copy_path_name(pSMB->FileName, fileName);
Steve French2d785a52007-07-15 01:48:57 +0000757 }
758
759 params = 6 + name_len;
760 pSMB->MaxParameterCount = cpu_to_le16(2);
761 pSMB->MaxDataCount = 0; /* BB double check this with jra */
762 pSMB->MaxSetupCount = 0;
763 pSMB->Reserved = 0;
764 pSMB->Flags = 0;
765 pSMB->Timeout = 0;
766 pSMB->Reserved2 = 0;
767 param_offset = offsetof(struct smb_com_transaction2_spi_req,
768 InformationLevel) - 4;
769 offset = param_offset + params;
770
Steve French7b09d4e2021-07-22 14:35:15 -0500771 /* Setup pointer to Request Data (inode type).
772 * Note that SMB offsets are from the beginning of SMB which is 4 bytes
773 * in, after RFC1001 field
774 */
775 pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4);
Steve French2d785a52007-07-15 01:48:57 +0000776 pRqD->type = cpu_to_le16(type);
777 pSMB->ParameterOffset = cpu_to_le16(param_offset);
778 pSMB->DataOffset = cpu_to_le16(offset);
779 pSMB->SetupCount = 1;
780 pSMB->Reserved3 = 0;
781 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
782 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
783
784 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
785 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
786 pSMB->ParameterCount = cpu_to_le16(params);
787 pSMB->TotalParameterCount = pSMB->ParameterCount;
788 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
789 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000790 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000791 pSMB->ByteCount = cpu_to_le16(byte_count);
792 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
793 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000794 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500795 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000796 cifs_buf_release(pSMB);
797
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400798 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000799
800 if (rc == -EAGAIN)
801 goto PsxDelete;
802
803 return rc;
804}
805
806int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700807CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
808 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
810 DELETE_FILE_REQ *pSMB = NULL;
811 DELETE_FILE_RSP *pSMBr = NULL;
812 int rc = 0;
813 int bytes_returned;
814 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500815 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817DelFileRetry:
818 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
819 (void **) &pSMBr);
820 if (rc)
821 return rc;
822
823 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700824 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
825 PATH_MAX, cifs_sb->local_nls,
826 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 name_len++; /* trailing null */
828 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000829 } else {
830 name_len = copy_path_name(pSMB->fileName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
832 pSMB->SearchAttributes =
833 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
834 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000835 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 pSMB->ByteCount = cpu_to_le16(name_len + 1);
837 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
838 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400839 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000840 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500841 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 cifs_buf_release(pSMB);
844 if (rc == -EAGAIN)
845 goto DelFileRetry;
846
847 return rc;
848}
849
850int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400851CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
852 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853{
854 DELETE_DIRECTORY_REQ *pSMB = NULL;
855 DELETE_DIRECTORY_RSP *pSMBr = NULL;
856 int rc = 0;
857 int bytes_returned;
858 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500859 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Joe Perchesf96637b2013-05-04 22:12:25 -0500861 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862RmDirRetry:
863 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
864 (void **) &pSMBr);
865 if (rc)
866 return rc;
867
868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400869 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
870 PATH_MAX, cifs_sb->local_nls,
871 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 name_len++; /* trailing null */
873 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000874 } else {
875 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 }
877
878 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000879 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 pSMB->ByteCount = cpu_to_le16(name_len + 1);
881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
882 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400883 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000884 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500885 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887 cifs_buf_release(pSMB);
888 if (rc == -EAGAIN)
889 goto RmDirRetry;
890 return rc;
891}
892
893int
Steve Frenchc3ca78e2019-09-25 00:32:13 -0500894CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
895 struct cifs_tcon *tcon, const char *name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300896 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
898 int rc = 0;
899 CREATE_DIRECTORY_REQ *pSMB = NULL;
900 CREATE_DIRECTORY_RSP *pSMBr = NULL;
901 int bytes_returned;
902 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500903 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Joe Perchesf96637b2013-05-04 22:12:25 -0500905 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906MkDirRetry:
907 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
908 (void **) &pSMBr);
909 if (rc)
910 return rc;
911
912 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600913 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300914 PATH_MAX, cifs_sb->local_nls,
915 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 name_len++; /* trailing null */
917 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000918 } else {
919 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
921
922 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000923 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 pSMB->ByteCount = cpu_to_le16(name_len + 1);
925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400927 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000928 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500929 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700930
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 cifs_buf_release(pSMB);
932 if (rc == -EAGAIN)
933 goto MkDirRetry;
934 return rc;
935}
936
Steve French2dd29d32007-04-23 22:07:35 +0000937int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400938CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
939 __u32 posix_flags, __u64 mode, __u16 *netfid,
940 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
941 const char *name, const struct nls_table *nls_codepage,
942 int remap)
Steve French2dd29d32007-04-23 22:07:35 +0000943{
944 TRANSACTION2_SPI_REQ *pSMB = NULL;
945 TRANSACTION2_SPI_RSP *pSMBr = NULL;
946 int name_len;
947 int rc = 0;
948 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +0000949 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +0000950 OPEN_PSX_REQ *pdata;
951 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +0000952
Joe Perchesf96637b2013-05-04 22:12:25 -0500953 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +0000954PsxCreat:
955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
959
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
961 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600962 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
963 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +0000964 name_len++; /* trailing null */
965 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000966 } else {
967 name_len = copy_path_name(pSMB->FileName, name);
Steve French2dd29d32007-04-23 22:07:35 +0000968 }
969
970 params = 6 + name_len;
971 count = sizeof(OPEN_PSX_REQ);
972 pSMB->MaxParameterCount = cpu_to_le16(2);
973 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
974 pSMB->MaxSetupCount = 0;
975 pSMB->Reserved = 0;
976 pSMB->Flags = 0;
977 pSMB->Timeout = 0;
978 pSMB->Reserved2 = 0;
979 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000980 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000981 offset = param_offset + params;
Steve French21a64912021-07-22 13:50:41 -0500982 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
983 pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000984 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +0000985 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000986 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000987 pdata->OpenFlags = cpu_to_le32(*pOplock);
988 pSMB->ParameterOffset = cpu_to_le16(param_offset);
989 pSMB->DataOffset = cpu_to_le16(offset);
990 pSMB->SetupCount = 1;
991 pSMB->Reserved3 = 0;
992 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
993 byte_count = 3 /* pad */ + params + count;
994
995 pSMB->DataCount = cpu_to_le16(count);
996 pSMB->ParameterCount = cpu_to_le16(params);
997 pSMB->TotalDataCount = pSMB->DataCount;
998 pSMB->TotalParameterCount = pSMB->ParameterCount;
999 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1000 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001001 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001002 pSMB->ByteCount = cpu_to_le16(byte_count);
1003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1005 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001006 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001007 goto psx_create_err;
1008 }
1009
Joe Perchesf96637b2013-05-04 22:12:25 -05001010 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001011 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1012
Jeff Layton820a8032011-05-04 08:05:26 -04001013 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001014 rc = -EIO; /* bad smb */
1015 goto psx_create_err;
1016 }
1017
1018 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001019 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001020 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001021
Steve French2dd29d32007-04-23 22:07:35 +00001022 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001023 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001024 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1025 /* Let caller know file was created so we can set the mode. */
1026 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001027 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001028 *pOplock |= CIFS_CREATE_ACTION;
1029 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001030 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1031 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001032 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001033 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001034 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001035 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001036 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001037 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001038 goto psx_create_err;
1039 }
Steve French50c2f752007-07-13 00:33:32 +00001040 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001041 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001042 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001043 }
Steve French2dd29d32007-04-23 22:07:35 +00001044
1045psx_create_err:
1046 cifs_buf_release(pSMB);
1047
Steve French65bc98b2009-07-10 15:27:25 +00001048 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001049 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001050 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001051 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001052
1053 if (rc == -EAGAIN)
1054 goto PsxCreat;
1055
Steve French50c2f752007-07-13 00:33:32 +00001056 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001057}
1058
Steve Frencha9d02ad2005-08-24 23:06:05 -07001059static __u16 convert_disposition(int disposition)
1060{
1061 __u16 ofun = 0;
1062
1063 switch (disposition) {
1064 case FILE_SUPERSEDE:
1065 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1066 break;
1067 case FILE_OPEN:
1068 ofun = SMBOPEN_OAPPEND;
1069 break;
1070 case FILE_CREATE:
1071 ofun = SMBOPEN_OCREATE;
1072 break;
1073 case FILE_OPEN_IF:
1074 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1075 break;
1076 case FILE_OVERWRITE:
1077 ofun = SMBOPEN_OTRUNC;
1078 break;
1079 case FILE_OVERWRITE_IF:
1080 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1081 break;
1082 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001083 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001084 ofun = SMBOPEN_OAPPEND; /* regular open */
1085 }
1086 return ofun;
1087}
1088
Jeff Layton35fc37d2008-05-14 10:22:03 -07001089static int
1090access_flags_to_smbopen_mode(const int access_flags)
1091{
1092 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1093
1094 if (masked_flags == GENERIC_READ)
1095 return SMBOPEN_READ;
1096 else if (masked_flags == GENERIC_WRITE)
1097 return SMBOPEN_WRITE;
1098
1099 /* just go for read/write */
1100 return SMBOPEN_READWRITE;
1101}
1102
Steve Frencha9d02ad2005-08-24 23:06:05 -07001103int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001104SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001105 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001106 const int access_flags, const int create_options, __u16 *netfid,
1107 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001108 const struct nls_table *nls_codepage, int remap)
1109{
Colin Ian King032e0912021-06-13 15:01:23 +01001110 int rc;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001111 OPENX_REQ *pSMB = NULL;
1112 OPENX_RSP *pSMBr = NULL;
1113 int bytes_returned;
1114 int name_len;
1115 __u16 count;
1116
1117OldOpenRetry:
1118 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1119 (void **) &pSMBr);
1120 if (rc)
1121 return rc;
1122
1123 pSMB->AndXCommand = 0xFF; /* none */
1124
1125 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1126 count = 1; /* account for one byte pad to word boundary */
1127 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001128 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1129 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001130 name_len++; /* trailing null */
1131 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001132 } else {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001133 count = 0; /* no pad */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001134 name_len = copy_path_name(pSMB->fileName, fileName);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001135 }
1136 if (*pOplock & REQ_OPLOCK)
1137 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001138 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001140
Steve Frencha9d02ad2005-08-24 23:06:05 -07001141 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001142 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001143 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1144 /* set file as system file if special file such
1145 as fifo and server expecting SFU style and
1146 no Unix extensions */
1147
Steve French790fe572007-07-07 19:25:05 +00001148 if (create_options & CREATE_OPTION_SPECIAL)
1149 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001150 else /* BB FIXME BB */
1151 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001152
Jeff Layton67750fb2008-05-09 22:28:02 +00001153 if (create_options & CREATE_OPTION_READONLY)
1154 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001155
1156 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001157/* pSMB->CreateOptions = cpu_to_le32(create_options &
1158 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001159 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001160
1161 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001162 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001164 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001165
1166 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001168 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001169 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001171 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001172 } else {
1173 /* BB verify if wct == 15 */
1174
Steve French582d21e2008-05-13 04:54:12 +00001175/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001176
1177 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1178 /* Let caller know file was created so we can set the mode. */
1179 /* Do we care about the CreateAction in any other cases? */
1180 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001181/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001182 *pOplock |= CIFS_CREATE_ACTION; */
1183 /* BB FIXME END */
1184
Steve French790fe572007-07-07 19:25:05 +00001185 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1187 pfile_info->LastAccessTime = 0; /* BB fixme */
1188 pfile_info->LastWriteTime = 0; /* BB fixme */
1189 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001190 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001191 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001192 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001193 pfile_info->AllocationSize =
1194 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1195 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001196 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001197 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001198 }
1199 }
1200
1201 cifs_buf_release(pSMB);
1202 if (rc == -EAGAIN)
1203 goto OldOpenRetry;
1204 return rc;
1205}
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001208CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1209 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210{
Colin Ian King1afdea42019-07-23 16:09:19 +01001211 int rc;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001212 OPEN_REQ *req = NULL;
1213 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 int bytes_returned;
1215 int name_len;
1216 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001217 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1218 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001219 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001220 const struct nls_table *nls = cifs_sb->local_nls;
1221 int create_options = oparms->create_options;
1222 int desired_access = oparms->desired_access;
1223 int disposition = oparms->disposition;
1224 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001227 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1228 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 if (rc)
1230 return rc;
1231
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001232 /* no commands go after this */
1233 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001235 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1236 /* account for one byte pad to word boundary */
1237 count = 1;
1238 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1239 path, PATH_MAX, nls, remap);
1240 /* trailing null */
1241 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001243 req->NameLength = cpu_to_le16(name_len);
1244 } else {
1245 /* BB improve check for buffer overruns BB */
1246 /* no pad */
1247 count = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001248 name_len = copy_path_name(req->fileName, path);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001249 req->NameLength = cpu_to_le16(name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001251
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001252 if (*oplock & REQ_OPLOCK)
1253 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1254 else if (*oplock & REQ_BATCHOPLOCK)
1255 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1256
1257 req->DesiredAccess = cpu_to_le32(desired_access);
1258 req->AllocationSize = 0;
1259
1260 /*
1261 * Set file as system file if special file such as fifo and server
1262 * expecting SFU style and no Unix extensions.
1263 */
1264 if (create_options & CREATE_OPTION_SPECIAL)
1265 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1266 else
1267 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1268
1269 /*
1270 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1271 * sensitive checks for other servers such as Samba.
1272 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001274 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Jeff Layton67750fb2008-05-09 22:28:02 +00001276 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001277 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001278
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001279 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1280 req->CreateDisposition = cpu_to_le32(disposition);
1281 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1282
Steve French09d1db52005-04-28 22:41:08 -07001283 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001284 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1285 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
1287 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001288 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001290 req->ByteCount = cpu_to_le16(count);
1291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1292 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001293 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001295 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001296 cifs_buf_release(req);
1297 if (rc == -EAGAIN)
1298 goto openRetry;
1299 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001301
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001302 /* 1 byte no need to le_to_cpu */
1303 *oplock = rsp->OplockLevel;
1304 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001305 oparms->fid->netfid = rsp->Fid;
Aurelien Aptel86f740f2020-02-21 11:19:06 +01001306 oparms->fid->access = desired_access;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001307
1308 /* Let caller know file was created so we can set the mode. */
1309 /* Do we care about the CreateAction in any other cases? */
1310 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1311 *oplock |= CIFS_CREATE_ACTION;
1312
1313 if (buf) {
1314 /* copy from CreationTime to Attributes */
1315 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1316 /* the file_info buf is endian converted by caller */
1317 buf->AllocationSize = rsp->AllocationSize;
1318 buf->EndOfFile = rsp->EndOfFile;
1319 buf->NumberOfLinks = cpu_to_le32(1);
1320 buf->DeletePending = 0;
1321 }
1322
1323 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 return rc;
1325}
1326
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001327/*
1328 * Discard any remaining data in the current SMB. To do this, we borrow the
1329 * current bigbuf.
1330 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001331int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001332cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001333{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001334 unsigned int rfclen = server->pdu_size;
1335 int remaining = rfclen + server->vals->header_preamble_size -
1336 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001337
1338 while (remaining > 0) {
1339 int length;
1340
David Howellscf0604a2021-02-04 00:15:21 -06001341 length = cifs_discard_from_socket(server,
1342 min_t(size_t, remaining,
1343 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001344 if (length < 0)
1345 return length;
1346 server->total_read += length;
1347 remaining -= length;
1348 }
1349
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001350 return 0;
1351}
1352
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001353static int
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001354__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1355 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001356{
1357 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001358
Pavel Shilovsky350be252017-04-10 10:31:33 -07001359 length = cifs_discard_remaining_data(server);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001360 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001361 mid->resp_buf = server->smallbuf;
1362 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001363 return length;
1364}
1365
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001366static int
1367cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1368{
1369 struct cifs_readdata *rdata = mid->callback_data;
1370
1371 return __cifs_readv_discard(server, mid, rdata->result);
1372}
1373
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001374int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001375cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1376{
1377 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001378 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001379 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001380 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001381 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001382 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001383 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001384
Joe Perchesf96637b2013-05-04 22:12:25 -05001385 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1386 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001387
1388 /*
1389 * read the rest of READ_RSP header (sans Data array), or whatever we
1390 * can if there's not enough data. At this point, we've read down to
1391 * the Mid.
1392 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001393 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001394 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001395
Al Viroa6137302016-01-09 19:37:16 -05001396 length = cifs_read_from_socket(server,
1397 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001398 if (length < 0)
1399 return length;
1400 server->total_read += length;
1401
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001402 if (server->ops->is_session_expired &&
1403 server->ops->is_session_expired(buf)) {
1404 cifs_reconnect(server);
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001405 return -1;
1406 }
1407
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001408 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -08001409 server->ops->is_status_pending(buf, server)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001410 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001411 return -1;
1412 }
1413
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001414 /* set up first two iov for signature check and to get credits */
1415 rdata->iov[0].iov_base = buf;
Pavel Shilovskybb1bccb2019-01-17 16:18:38 -08001416 rdata->iov[0].iov_len = server->vals->header_preamble_size;
1417 rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1418 rdata->iov[1].iov_len =
1419 server->total_read - server->vals->header_preamble_size;
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001420 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1421 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1422 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1423 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1424
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001426 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001428 cifs_dbg(FYI, "%s: server returned error %d\n",
1429 __func__, rdata->result);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001430 /* normal error on read response */
1431 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432 }
1433
1434 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001435 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001436 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1437 __func__, server->total_read,
1438 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001439 rdata->result = -EIO;
1440 return cifs_readv_discard(server, mid);
1441 }
1442
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001443 data_offset = server->ops->read_data_offset(buf) +
1444 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001445 if (data_offset < server->total_read) {
1446 /*
1447 * win2k8 sometimes sends an offset of 0 when the read
1448 * is beyond the EOF. Treat it as if the data starts just after
1449 * the header.
1450 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001451 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1452 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453 data_offset = server->total_read;
1454 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1455 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001456 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1457 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001458 rdata->result = -EIO;
1459 return cifs_readv_discard(server, mid);
1460 }
1461
Joe Perchesf96637b2013-05-04 22:12:25 -05001462 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1463 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001464
1465 len = data_offset - server->total_read;
1466 if (len > 0) {
1467 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001468 length = cifs_read_from_socket(server,
1469 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001470 if (length < 0)
1471 return length;
1472 server->total_read += length;
1473 }
1474
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001475 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001476#ifdef CONFIG_CIFS_SMB_DIRECT
1477 use_rdma_mr = rdata->mr;
1478#endif
1479 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1480 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 /* data_len is corrupt -- discard frame */
1482 rdata->result = -EIO;
1483 return cifs_readv_discard(server, mid);
1484 }
1485
Jeff Layton8321fec2012-09-19 06:22:32 -07001486 length = rdata->read_into_pages(server, rdata, data_len);
1487 if (length < 0)
1488 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489
Jeff Layton8321fec2012-09-19 06:22:32 -07001490 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001491
Joe Perchesf96637b2013-05-04 22:12:25 -05001492 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1493 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001494
1495 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001496 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001497 return cifs_readv_discard(server, mid);
1498
1499 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001500 mid->resp_buf = server->smallbuf;
1501 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001502 return length;
1503}
1504
1505static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506cifs_readv_callback(struct mid_q_entry *mid)
1507{
1508 struct cifs_readdata *rdata = mid->callback_data;
1509 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1510 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001511 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1512 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001513 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001514 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001515 .rq_npages = rdata->nr_pages,
1516 .rq_pagesz = rdata->pagesz,
1517 .rq_tailsz = rdata->tailsz };
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001518 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519
Joe Perchesf96637b2013-05-04 22:12:25 -05001520 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1521 __func__, mid->mid, mid->mid_state, rdata->result,
1522 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001523
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001524 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001525 case MID_RESPONSE_RECEIVED:
1526 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001527 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001528 int rc = 0;
1529
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001530 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001531 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001532 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001533 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1534 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001535 }
1536 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001537 task_io_account_read(rdata->got_bytes);
1538 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001539 break;
1540 case MID_REQUEST_SUBMITTED:
1541 case MID_RETRY_NEEDED:
1542 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001543 if (server->sign && rdata->got_bytes)
1544 /* reset bytes number since we can not check a sign */
1545 rdata->got_bytes = 0;
1546 /* FIXME: should this be counted toward the initiating task? */
1547 task_io_account_read(rdata->got_bytes);
1548 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549 break;
1550 default:
1551 rdata->result = -EIO;
1552 }
1553
Jeff Laytonda472fc2012-03-23 14:40:53 -04001554 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001555 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001556 add_credits(server, &credits, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557}
1558
1559/* cifs_async_readv - send an async write, and set up mid to handle result */
1560int
1561cifs_async_readv(struct cifs_readdata *rdata)
1562{
1563 int rc;
1564 READ_REQ *smb = NULL;
1565 int wct;
1566 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001567 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1568 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001569
Joe Perchesf96637b2013-05-04 22:12:25 -05001570 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1571 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572
1573 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1574 wct = 12;
1575 else {
1576 wct = 10; /* old style read */
1577 if ((rdata->offset >> 32) > 0) {
1578 /* can not handle this big offset for old */
1579 return -EIO;
1580 }
1581 }
1582
1583 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1584 if (rc)
1585 return rc;
1586
1587 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1588 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1589
1590 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001591 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001592 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1593 if (wct == 12)
1594 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1595 smb->Remaining = 0;
1596 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1597 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1598 if (wct == 12)
1599 smb->ByteCount = 0;
1600 else {
1601 /* old style read */
1602 struct smb_com_readx_req *smbr =
1603 (struct smb_com_readx_req *)smb;
1604 smbr->ByteCount = 0;
1605 }
1606
1607 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001608 rdata->iov[0].iov_base = smb;
1609 rdata->iov[0].iov_len = 4;
1610 rdata->iov[1].iov_base = (char *)smb + 4;
1611 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001612
Jeff Layton6993f742012-05-16 07:13:17 -04001613 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001614 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08001615 cifs_readv_callback, NULL, rdata, 0, NULL);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001616
1617 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001618 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001619 else
1620 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001621
1622 cifs_small_buf_release(smb);
1623 return rc;
1624}
1625
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001627CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1628 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629{
1630 int rc = -EACCES;
1631 READ_REQ *pSMB = NULL;
1632 READ_RSP *pSMBr = NULL;
1633 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001634 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001635 int resp_buf_type = 0;
1636 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001637 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001638 __u32 pid = io_parms->pid;
1639 __u16 netfid = io_parms->netfid;
1640 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001641 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001642 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Joe Perchesf96637b2013-05-04 22:12:25 -05001644 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001645 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001646 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001647 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001648 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001649 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001650 /* can not handle this big offset for old */
1651 return -EIO;
1652 }
1653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001656 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 if (rc)
1658 return rc;
1659
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001660 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1661 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 /* tcon and ses pointer are checked in smb_init */
1664 if (tcon->ses->server == NULL)
1665 return -ECONNABORTED;
1666
Steve Frenchec637e32005-12-12 20:53:18 -08001667 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001669 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001670 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001671 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 pSMB->Remaining = 0;
1674 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1675 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001676 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001677 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1678 else {
1679 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001680 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001681 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001682 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001683 }
Steve Frenchec637e32005-12-12 20:53:18 -08001684
1685 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001686 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001687 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1688 CIFS_LOG_ERROR, &rsp_iov);
1689 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001690 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001691 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001693 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 } else {
1695 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1696 data_length = data_length << 16;
1697 data_length += le16_to_cpu(pSMBr->DataLength);
1698 *nbytes = data_length;
1699
1700 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001701 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001703 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001704 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 rc = -EIO;
1706 *nbytes = 0;
1707 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001708 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001709 le16_to_cpu(pSMBr->DataOffset);
1710/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001711 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001712 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001713 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001714 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001715 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 }
1717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
Steve French790fe572007-07-07 19:25:05 +00001719 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001720 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001721 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001722 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001723 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001724 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001725 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001726 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001727 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001728 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001729
1730 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 since file handle passed in no longer valid */
1732 return rc;
1733}
1734
Steve Frenchec637e32005-12-12 20:53:18 -08001735
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001737CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001738 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739{
1740 int rc = -EACCES;
1741 WRITE_REQ *pSMB = NULL;
1742 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001743 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 __u32 bytes_sent;
1745 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001746 __u32 pid = io_parms->pid;
1747 __u16 netfid = io_parms->netfid;
1748 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001749 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001750 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
Steve Frencha24e2d72010-04-03 17:20:21 +00001752 *nbytes = 0;
1753
Joe Perchesf96637b2013-05-04 22:12:25 -05001754 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001755 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001756 return -ECONNABORTED;
1757
Steve French790fe572007-07-07 19:25:05 +00001758 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001759 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001760 else {
Steve French1c955182005-08-30 20:58:07 -07001761 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001762 if ((offset >> 32) > 0) {
1763 /* can not handle big offset for old srv */
1764 return -EIO;
1765 }
1766 }
Steve French1c955182005-08-30 20:58:07 -07001767
1768 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 (void **) &pSMBr);
1770 if (rc)
1771 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001772
1773 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
1780 pSMB->AndXCommand = 0xFF; /* none */
1781 pSMB->Fid = netfid;
1782 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001783 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001784 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 pSMB->Reserved = 0xFFFFFFFF;
1787 pSMB->WriteMode = 0;
1788 pSMB->Remaining = 0;
1789
Steve French50c2f752007-07-13 00:33:32 +00001790 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 can send more if LARGE_WRITE_X capability returned by the server and if
1792 our buffer is big enough or if we convert to iovecs on socket writes
1793 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001794 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1796 } else {
1797 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1798 & ~0xFF;
1799 }
1800
1801 if (bytes_sent > count)
1802 bytes_sent = count;
1803 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001804 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001805 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001806 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001807 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 /* No buffer */
1809 cifs_buf_release(pSMB);
1810 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001811 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001812 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001813 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001814 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001815 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001816
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1818 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001819 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001820
Steve French790fe572007-07-07 19:25:05 +00001821 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001822 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001823 else { /* old style write has byte count 4 bytes earlier
1824 so 4 bytes pad */
1825 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001826 (struct smb_com_writex_req *)pSMB;
1827 pSMBW->ByteCount = cpu_to_le16(byte_count);
1828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
1830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001832 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001834 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 } else {
1836 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1837 *nbytes = (*nbytes) << 16;
1838 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301839
1840 /*
1841 * Mask off high 16 bits when bytes written as returned by the
1842 * server is greater than bytes requested by the client. Some
1843 * OS/2 servers are known to set incorrect CountHigh values.
1844 */
1845 if (*nbytes > count)
1846 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 }
1848
1849 cifs_buf_release(pSMB);
1850
Steve French50c2f752007-07-13 00:33:32 +00001851 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 since file handle passed in no longer valid */
1853
1854 return rc;
1855}
1856
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001857void
1858cifs_writedata_release(struct kref *refcount)
1859{
1860 struct cifs_writedata *wdata = container_of(refcount,
1861 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001862#ifdef CONFIG_CIFS_SMB_DIRECT
1863 if (wdata->mr) {
1864 smbd_deregister_mr(wdata->mr);
1865 wdata->mr = NULL;
1866 }
1867#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001868
1869 if (wdata->cfile)
1870 cifsFileInfo_put(wdata->cfile);
1871
Long Li8e7360f2018-05-30 12:47:56 -07001872 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001873 kfree(wdata);
1874}
1875
1876/*
1877 * Write failed with a retryable error. Resend the write request. It's also
1878 * possible that the page was redirtied so re-clean the page.
1879 */
1880static void
1881cifs_writev_requeue(struct cifs_writedata *wdata)
1882{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001883 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001884 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001885 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001886 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001887
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001888 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1889 i = 0;
1890 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001891 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001892 struct cifs_writedata *wdata2;
1893 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001894
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001895 wsize = server->ops->wp_retry_size(inode);
1896 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001897 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001898 if (!nr_pages) {
1899 rc = -ENOTSUPP;
1900 break;
1901 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001902 cur_len = nr_pages * PAGE_SIZE;
1903 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001904 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001905 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001906 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001907 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001908 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001909
1910 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1911 if (!wdata2) {
1912 rc = -ENOMEM;
1913 break;
1914 }
1915
1916 for (j = 0; j < nr_pages; j++) {
1917 wdata2->pages[j] = wdata->pages[i + j];
1918 lock_page(wdata2->pages[j]);
1919 clear_page_dirty_for_io(wdata2->pages[j]);
1920 }
1921
1922 wdata2->sync_mode = wdata->sync_mode;
1923 wdata2->nr_pages = nr_pages;
1924 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001925 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001926 wdata2->tailsz = tailsz;
1927 wdata2->bytes = cur_len;
1928
Aurelien Aptel86f740f2020-02-21 11:19:06 +01001929 rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08001930 &wdata2->cfile);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001931 if (!wdata2->cfile) {
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08001932 cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
1933 rc);
1934 if (!is_retryable_error(rc))
1935 rc = -EBADF;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08001936 } else {
1937 wdata2->pid = wdata2->cfile->pid;
1938 rc = server->ops->async_writev(wdata2,
1939 cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001940 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001941
1942 for (j = 0; j < nr_pages; j++) {
1943 unlock_page(wdata2->pages[j]);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08001944 if (rc != 0 && !is_retryable_error(rc)) {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001945 SetPageError(wdata2->pages[j]);
1946 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001947 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001948 }
1949 }
1950
Adam McCoya4813792020-05-13 11:53:30 +00001951 kref_put(&wdata2->refcount, cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001952 if (rc) {
Pavel Shilovsky9a663962019-01-08 11:15:28 -08001953 if (is_retryable_error(rc))
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001954 continue;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08001955 i += nr_pages;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001956 break;
1957 }
1958
1959 rest_len -= cur_len;
1960 i += nr_pages;
1961 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001962
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08001963 /* cleanup remaining pages from the original wdata */
1964 for (; i < wdata->nr_pages; i++) {
1965 SetPageError(wdata->pages[i]);
1966 end_page_writeback(wdata->pages[i]);
1967 put_page(wdata->pages[i]);
1968 }
1969
Pavel Shilovsky9a663962019-01-08 11:15:28 -08001970 if (rc != 0 && !is_retryable_error(rc))
1971 mapping_set_error(inode->i_mapping, rc);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001972 kref_put(&wdata->refcount, cifs_writedata_release);
1973}
1974
Jeff Laytonc2e87642012-03-23 14:40:55 -04001975void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976cifs_writev_complete(struct work_struct *work)
1977{
1978 struct cifs_writedata *wdata = container_of(work,
1979 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00001980 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001981 int i = 0;
1982
1983 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001984 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001985 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001986 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001987 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1988 wdata->bytes);
1989 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1990 return cifs_writev_requeue(wdata);
1991
1992 for (i = 0; i < wdata->nr_pages; i++) {
1993 struct page *page = wdata->pages[i];
1994 if (wdata->result == -EAGAIN)
1995 __set_page_dirty_nobuffers(page);
1996 else if (wdata->result < 0)
1997 SetPageError(page);
1998 end_page_writeback(page);
Shyam Prasad N18d04062021-08-10 10:22:28 +00001999 cifs_readpage_to_fscache(inode, page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002000 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002001 }
2002 if (wdata->result != -EAGAIN)
2003 mapping_set_error(inode->i_mapping, wdata->result);
2004 kref_put(&wdata->refcount, cifs_writedata_release);
2005}
2006
2007struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002008cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002009{
Long Li8e7360f2018-05-30 12:47:56 -07002010 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002011 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002012 if (pages)
2013 return cifs_writedata_direct_alloc(pages, complete);
2014
2015 return NULL;
2016}
2017
2018struct cifs_writedata *
2019cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2020{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002021 struct cifs_writedata *wdata;
2022
Long Li8e7360f2018-05-30 12:47:56 -07002023 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002024 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002025 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002026 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002027 INIT_LIST_HEAD(&wdata->list);
2028 init_completion(&wdata->done);
2029 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002030 }
2031 return wdata;
2032}
2033
2034/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002035 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002036 * workqueue completion task.
2037 */
2038static void
2039cifs_writev_callback(struct mid_q_entry *mid)
2040{
2041 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002042 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002043 unsigned int written;
2044 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002045 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002046
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002047 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002048 case MID_RESPONSE_RECEIVED:
2049 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2050 if (wdata->result != 0)
2051 break;
2052
2053 written = le16_to_cpu(smb->CountHigh);
2054 written <<= 16;
2055 written += le16_to_cpu(smb->Count);
2056 /*
2057 * Mask off high 16 bits when bytes written as returned
2058 * by the server is greater than bytes requested by the
2059 * client. OS/2 servers are known to set incorrect
2060 * CountHigh values.
2061 */
2062 if (written > wdata->bytes)
2063 written &= 0xFFFF;
2064
2065 if (written < wdata->bytes)
2066 wdata->result = -ENOSPC;
2067 else
2068 wdata->bytes = written;
2069 break;
2070 case MID_REQUEST_SUBMITTED:
2071 case MID_RETRY_NEEDED:
2072 wdata->result = -EAGAIN;
2073 break;
2074 default:
2075 wdata->result = -EIO;
2076 break;
2077 }
2078
Jeff Laytonda472fc2012-03-23 14:40:53 -04002079 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002081 add_credits(tcon->ses->server, &credits, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082}
2083
2084/* cifs_async_writev - send an async write, and set up mid to handle result */
2085int
Steve French4a5c80d2014-02-07 20:45:12 -06002086cifs_async_writev(struct cifs_writedata *wdata,
2087 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002088{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002089 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002090 WRITE_REQ *smb = NULL;
2091 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002092 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002093 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002094 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095
2096 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2097 wct = 14;
2098 } else {
2099 wct = 12;
2100 if (wdata->offset >> 32 > 0) {
2101 /* can not handle big offset for old srv */
2102 return -EIO;
2103 }
2104 }
2105
2106 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2107 if (rc)
2108 goto async_writev_out;
2109
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002110 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2111 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002112
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002113 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002114 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002115 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2116 if (wct == 14)
2117 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2118 smb->Reserved = 0xFFFFFFFF;
2119 smb->WriteMode = 0;
2120 smb->Remaining = 0;
2121
2122 smb->DataOffset =
2123 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2124
2125 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002126 iov[0].iov_len = 4;
2127 iov[0].iov_base = smb;
2128 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2129 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002130
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002131 rqst.rq_iov = iov;
2132 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002133 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002134 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002135 rqst.rq_npages = wdata->nr_pages;
2136 rqst.rq_pagesz = wdata->pagesz;
2137 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002138
Joe Perchesf96637b2013-05-04 22:12:25 -05002139 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2140 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002141
2142 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2143 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2144
2145 if (wct == 14) {
2146 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2147 put_bcc(wdata->bytes + 1, &smb->hdr);
2148 } else {
2149 /* wct == 12 */
2150 struct smb_com_writex_req *smbw =
2151 (struct smb_com_writex_req *)smb;
2152 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2153 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002154 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002155 }
2156
2157 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002158 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08002159 cifs_writev_callback, NULL, wdata, 0, NULL);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002160
2161 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002162 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002163 else
Steve French4a5c80d2014-02-07 20:45:12 -06002164 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002165
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002166async_writev_out:
2167 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002168 return rc;
2169}
2170
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002171int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002172CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002173 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174{
Colin Ian King136a5dc2020-05-27 13:50:31 +01002175 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002177 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002178 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002179 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002180 __u32 pid = io_parms->pid;
2181 __u16 netfid = io_parms->netfid;
2182 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002183 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002184 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002185 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002187 *nbytes = 0;
2188
Joe Perchesf96637b2013-05-04 22:12:25 -05002189 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002190
Steve French4c3130e2008-12-09 00:28:16 +00002191 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002192 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002193 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002194 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002195 if ((offset >> 32) > 0) {
2196 /* can not handle big offset for old srv */
2197 return -EIO;
2198 }
2199 }
Steve French8cc64c62005-10-03 13:49:43 -07002200 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 if (rc)
2202 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002203
2204 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2205 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2206
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 /* tcon and ses pointer are checked in smb_init */
2208 if (tcon->ses->server == NULL)
2209 return -ECONNABORTED;
2210
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002211 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 pSMB->Fid = netfid;
2213 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002214 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002215 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 pSMB->Reserved = 0xFFFFFFFF;
2217 pSMB->WriteMode = 0;
2218 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002219
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002221 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Steve French3e844692005-10-03 13:37:24 -07002223 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2224 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002225 /* header + 1 byte pad */
2226 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002227 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002228 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002229 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002230 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002231 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002232 pSMB->ByteCount = cpu_to_le16(count + 1);
2233 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002234 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002235 (struct smb_com_writex_req *)pSMB;
2236 pSMBW->ByteCount = cpu_to_le16(count + 5);
2237 }
Steve French3e844692005-10-03 13:37:24 -07002238 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002239 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002240 iov[0].iov_len = smb_hdr_len + 4;
2241 else /* wct == 12 pad bigger by four bytes */
2242 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002243
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002244 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2245 &rsp_iov);
2246 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002247 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002249 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002250 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002251 /* presumably this can not happen, but best to be safe */
2252 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002253 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002254 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002255 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2256 *nbytes = (*nbytes) << 16;
2257 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302258
2259 /*
2260 * Mask off high 16 bits when bytes written as returned by the
2261 * server is greater than bytes requested by the client. OS/2
2262 * servers are known to set incorrect CountHigh values.
2263 */
2264 if (*nbytes > count)
2265 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002268 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
Steve French50c2f752007-07-13 00:33:32 +00002270 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 since file handle passed in no longer valid */
2272
2273 return rc;
2274}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002275
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002276int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2277 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002278 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2279{
2280 int rc = 0;
2281 LOCK_REQ *pSMB = NULL;
2282 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002283 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002284 int resp_buf_type;
2285 __u16 count;
2286
Joe Perchesf96637b2013-05-04 22:12:25 -05002287 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2288 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002289
2290 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2291 if (rc)
2292 return rc;
2293
2294 pSMB->Timeout = 0;
2295 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2296 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2297 pSMB->LockType = lock_type;
2298 pSMB->AndXCommand = 0xFF; /* none */
2299 pSMB->Fid = netfid; /* netfid stays le */
2300
2301 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2302 inc_rfc1001_len(pSMB, count);
2303 pSMB->ByteCount = cpu_to_le16(count);
2304
2305 iov[0].iov_base = (char *)pSMB;
2306 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2307 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2308 iov[1].iov_base = (char *)buf;
2309 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2310
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002311 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002312 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
2313 CIFS_NO_RSP_BUF, &rsp_iov);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002314 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002315 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002316 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002317
2318 return rc;
2319}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002320
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002322CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002323 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002325 const __u32 numLock, const __u8 lockType,
2326 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327{
2328 int rc = 0;
2329 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002330/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002332 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 __u16 count;
2334
Joe Perchesf96637b2013-05-04 22:12:25 -05002335 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2336 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002337 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2338
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 if (rc)
2340 return rc;
2341
Steve French790fe572007-07-07 19:25:05 +00002342 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002343 /* no response expected */
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002344 flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002346 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002347 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2349 } else {
2350 pSMB->Timeout = 0;
2351 }
2352
2353 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2354 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2355 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002356 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 pSMB->AndXCommand = 0xFF; /* none */
2358 pSMB->Fid = smb_file_id; /* netfid stays le */
2359
Steve French790fe572007-07-07 19:25:05 +00002360 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002361 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 /* BB where to store pid high? */
2363 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2364 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2365 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2366 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2367 count = sizeof(LOCKING_ANDX_RANGE);
2368 } else {
2369 /* oplock break */
2370 count = 0;
2371 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002372 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 pSMB->ByteCount = cpu_to_le16(count);
2374
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002375 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002376 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002377 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002378 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002379 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002380 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002381 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002382 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002383 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
Steve French50c2f752007-07-13 00:33:32 +00002385 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 since file handle passed in no longer valid */
2387 return rc;
2388}
2389
2390int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002391CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002392 const __u16 smb_file_id, const __u32 netpid,
2393 const loff_t start_offset, const __u64 len,
2394 struct file_lock *pLockData, const __u16 lock_type,
2395 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002396{
2397 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2398 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002399 struct cifs_posix_lock *parm_data;
2400 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002401 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002402 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002403 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002404 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002405 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002406 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002407
Joe Perchesf96637b2013-05-04 22:12:25 -05002408 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002409
Steve French08547b02006-02-28 22:39:25 +00002410 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2411
2412 if (rc)
2413 return rc;
2414
2415 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2416
Steve French50c2f752007-07-13 00:33:32 +00002417 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002418 pSMB->MaxSetupCount = 0;
2419 pSMB->Reserved = 0;
2420 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002421 pSMB->Reserved2 = 0;
2422 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2423 offset = param_offset + params;
2424
Steve French08547b02006-02-28 22:39:25 +00002425 count = sizeof(struct cifs_posix_lock);
2426 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002427 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002428 pSMB->SetupCount = 1;
2429 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002430 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002431 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2432 else
2433 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2434 byte_count = 3 /* pad */ + params + count;
2435 pSMB->DataCount = cpu_to_le16(count);
2436 pSMB->ParameterCount = cpu_to_le16(params);
2437 pSMB->TotalDataCount = pSMB->DataCount;
2438 pSMB->TotalParameterCount = pSMB->ParameterCount;
2439 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve Frenchd4dc2772021-07-07 14:03:54 -05002440 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
Steve French50c2f752007-07-13 00:33:32 +00002441 parm_data = (struct cifs_posix_lock *)
Steve Frenchd4dc2772021-07-07 14:03:54 -05002442 (((char *)pSMB) + offset + 4);
Steve French08547b02006-02-28 22:39:25 +00002443
2444 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002445 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002446 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002447 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002448 pSMB->Timeout = cpu_to_le32(-1);
2449 } else
2450 pSMB->Timeout = 0;
2451
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002452 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002453 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002454 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002455
2456 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002457 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002458 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2459 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002460 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002461 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002462 if (waitFlag) {
2463 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2464 (struct smb_hdr *) pSMBr, &bytes_returned);
2465 } else {
Steve French133672e2007-11-13 22:41:37 +00002466 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002467 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002468 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002469 &resp_buf_type, timeout, &rsp_iov);
2470 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002471 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002472 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002473
Steve French08547b02006-02-28 22:39:25 +00002474 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002475 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002476 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002477 /* lock structure can be returned on get */
2478 __u16 data_offset;
2479 __u16 data_count;
2480 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002481
Jeff Layton820a8032011-05-04 08:05:26 -04002482 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002483 rc = -EIO; /* bad smb */
2484 goto plk_err_exit;
2485 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002486 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2487 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002488 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002489 rc = -EIO;
2490 goto plk_err_exit;
2491 }
2492 parm_data = (struct cifs_posix_lock *)
2493 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002494 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002495 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002496 else {
2497 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002498 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002499 pLockData->fl_type = F_RDLCK;
2500 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002501 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002502 pLockData->fl_type = F_WRLCK;
2503
Steve French5443d132011-03-13 05:08:25 +00002504 pLockData->fl_start = le64_to_cpu(parm_data->start);
2505 pLockData->fl_end = pLockData->fl_start +
2506 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002507 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002508 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002509 }
Steve French50c2f752007-07-13 00:33:32 +00002510
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002511plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002512 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002513
Steve French08547b02006-02-28 22:39:25 +00002514 /* Note: On -EAGAIN error only caller can retry on handle based calls
2515 since file handle passed in no longer valid */
2516
2517 return rc;
2518}
2519
2520
2521int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002522CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
2524 int rc = 0;
2525 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002526 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
2528/* do not retry on dead session on close */
2529 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002530 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 return 0;
2532 if (rc)
2533 return rc;
2534
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002536 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002538 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002539 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002540 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002542 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002544 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
2546 }
2547
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002549 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 rc = 0;
2551
2552 return rc;
2553}
2554
2555int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002556CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002557{
2558 int rc = 0;
2559 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002560 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002561
2562 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2563 if (rc)
2564 return rc;
2565
2566 pSMB->FileID = (__u16) smb_file_id;
2567 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002568 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002569 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002570 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002571 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002572 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002573
2574 return rc;
2575}
2576
2577int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002578CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002579 const char *from_name, const char *to_name,
2580 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581{
2582 int rc = 0;
2583 RENAME_REQ *pSMB = NULL;
2584 RENAME_RSP *pSMBr = NULL;
2585 int bytes_returned;
2586 int name_len, name_len2;
2587 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002588 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
Joe Perchesf96637b2013-05-04 22:12:25 -05002590 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591renameRetry:
2592 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2593 (void **) &pSMBr);
2594 if (rc)
2595 return rc;
2596
2597 pSMB->BufferFormat = 0x04;
2598 pSMB->SearchAttributes =
2599 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2600 ATTR_DIRECTORY);
2601
2602 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002603 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2604 from_name, PATH_MAX,
2605 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 name_len++; /* trailing null */
2607 name_len *= 2;
2608 pSMB->OldFileName[name_len] = 0x04; /* pad */
2609 /* protocol requires ASCII signature byte on Unicode string */
2610 pSMB->OldFileName[name_len + 1] = 0x00;
2611 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002612 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002613 to_name, PATH_MAX, cifs_sb->local_nls,
2614 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2616 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002617 } else {
2618 name_len = copy_path_name(pSMB->OldFileName, from_name);
2619 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 name_len2++; /* signature byte */
2622 }
2623
2624 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002625 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 pSMB->ByteCount = cpu_to_le16(count);
2627
2628 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2629 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002630 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002631 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002632 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 cifs_buf_release(pSMB);
2635
2636 if (rc == -EAGAIN)
2637 goto renameRetry;
2638
2639 return rc;
2640}
2641
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002642int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002643 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002644 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645{
2646 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2647 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002648 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 char *data_offset;
2650 char dummy_string[30];
2651 int rc = 0;
2652 int bytes_returned = 0;
2653 int len_of_str;
2654 __u16 params, param_offset, offset, count, byte_count;
2655
Joe Perchesf96637b2013-05-04 22:12:25 -05002656 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2658 (void **) &pSMBr);
2659 if (rc)
2660 return rc;
2661
2662 params = 6;
2663 pSMB->MaxSetupCount = 0;
2664 pSMB->Reserved = 0;
2665 pSMB->Flags = 0;
2666 pSMB->Timeout = 0;
2667 pSMB->Reserved2 = 0;
2668 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2669 offset = param_offset + params;
2670
Steve Frenchf3717932021-07-07 13:34:47 -05002671 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2672 data_offset = (char *)(pSMB) + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 rename_info = (struct set_file_rename *) data_offset;
2674 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002675 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 pSMB->SetupCount = 1;
2677 pSMB->Reserved3 = 0;
2678 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2679 byte_count = 3 /* pad */ + params;
2680 pSMB->ParameterCount = cpu_to_le16(params);
2681 pSMB->TotalParameterCount = pSMB->ParameterCount;
2682 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2683 pSMB->DataOffset = cpu_to_le16(offset);
2684 /* construct random name ".cifs_tmp<inodenum><mid>" */
2685 rename_info->overwrite = cpu_to_le32(1);
2686 rename_info->root_fid = 0;
2687 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002688 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002689 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002690 len_of_str =
2691 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002692 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002694 len_of_str =
2695 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002696 target_name, PATH_MAX, nls_codepage,
2697 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 }
2699 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002700 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 byte_count += count;
2702 pSMB->DataCount = cpu_to_le16(count);
2703 pSMB->TotalDataCount = pSMB->DataCount;
2704 pSMB->Fid = netfid;
2705 pSMB->InformationLevel =
2706 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2707 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002708 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 pSMB->ByteCount = cpu_to_le16(byte_count);
2710 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002711 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002712 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002713 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002714 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2715 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002716
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 cifs_buf_release(pSMB);
2718
2719 /* Note: On -EAGAIN error only caller can retry on handle based calls
2720 since file handle passed in no longer valid */
2721
2722 return rc;
2723}
2724
2725int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002726CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2727 const char *fromName, const __u16 target_tid, const char *toName,
2728 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 int rc = 0;
2731 COPY_REQ *pSMB = NULL;
2732 COPY_RSP *pSMBr = NULL;
2733 int bytes_returned;
2734 int name_len, name_len2;
2735 __u16 count;
2736
Joe Perchesf96637b2013-05-04 22:12:25 -05002737 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738copyRetry:
2739 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2740 (void **) &pSMBr);
2741 if (rc)
2742 return rc;
2743
2744 pSMB->BufferFormat = 0x04;
2745 pSMB->Tid2 = target_tid;
2746
2747 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2748
2749 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002750 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2751 fromName, PATH_MAX, nls_codepage,
2752 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 name_len++; /* trailing null */
2754 name_len *= 2;
2755 pSMB->OldFileName[name_len] = 0x04; /* pad */
2756 /* protocol requires ASCII signature byte on Unicode string */
2757 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002758 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002759 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2760 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2762 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002763 } else {
2764 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002766 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 name_len2++; /* signature byte */
2768 }
2769
2770 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002771 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 pSMB->ByteCount = cpu_to_le16(count);
2773
2774 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2775 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2776 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002777 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2778 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 }
Steve French0d817bc2008-05-22 02:02:03 +00002780 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
2782 if (rc == -EAGAIN)
2783 goto copyRetry;
2784
2785 return rc;
2786}
2787
2788int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002789CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002791 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792{
2793 TRANSACTION2_SPI_REQ *pSMB = NULL;
2794 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2795 char *data_offset;
2796 int name_len;
2797 int name_len_target;
2798 int rc = 0;
2799 int bytes_returned = 0;
2800 __u16 params, param_offset, offset, byte_count;
2801
Joe Perchesf96637b2013-05-04 22:12:25 -05002802 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803createSymLinkRetry:
2804 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2805 (void **) &pSMBr);
2806 if (rc)
2807 return rc;
2808
2809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2810 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002811 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2812 /* find define for this maxpathcomponent */
2813 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 name_len++; /* trailing null */
2815 name_len *= 2;
2816
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002817 } else {
2818 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 }
2820 params = 6 + name_len;
2821 pSMB->MaxSetupCount = 0;
2822 pSMB->Reserved = 0;
2823 pSMB->Flags = 0;
2824 pSMB->Timeout = 0;
2825 pSMB->Reserved2 = 0;
2826 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002827 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 offset = param_offset + params;
2829
Steve Frenchded2d992021-07-01 20:44:27 -05002830 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2831 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2833 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002834 cifsConvertToUTF16((__le16 *) data_offset, toName,
2835 /* find define for this maxpathcomponent */
2836 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 name_len_target++; /* trailing null */
2838 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002839 } else {
2840 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 }
2842
2843 pSMB->MaxParameterCount = cpu_to_le16(2);
2844 /* BB find exact max on data count below from sess */
2845 pSMB->MaxDataCount = cpu_to_le16(1000);
2846 pSMB->SetupCount = 1;
2847 pSMB->Reserved3 = 0;
2848 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2849 byte_count = 3 /* pad */ + params + name_len_target;
2850 pSMB->DataCount = cpu_to_le16(name_len_target);
2851 pSMB->ParameterCount = cpu_to_le16(params);
2852 pSMB->TotalDataCount = pSMB->DataCount;
2853 pSMB->TotalParameterCount = pSMB->ParameterCount;
2854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2855 pSMB->DataOffset = cpu_to_le16(offset);
2856 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2857 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002858 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 pSMB->ByteCount = cpu_to_le16(byte_count);
2860 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2861 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002862 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002863 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002864 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2865 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
Steve French0d817bc2008-05-22 02:02:03 +00002867 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869 if (rc == -EAGAIN)
2870 goto createSymLinkRetry;
2871
2872 return rc;
2873}
2874
2875int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002876CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002878 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879{
2880 TRANSACTION2_SPI_REQ *pSMB = NULL;
2881 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2882 char *data_offset;
2883 int name_len;
2884 int name_len_target;
2885 int rc = 0;
2886 int bytes_returned = 0;
2887 __u16 params, param_offset, offset, byte_count;
2888
Joe Perchesf96637b2013-05-04 22:12:25 -05002889 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890createHardLinkRetry:
2891 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2892 (void **) &pSMBr);
2893 if (rc)
2894 return rc;
2895
2896 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002897 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2898 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 name_len++; /* trailing null */
2900 name_len *= 2;
2901
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002902 } else {
2903 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 }
2905 params = 6 + name_len;
2906 pSMB->MaxSetupCount = 0;
2907 pSMB->Reserved = 0;
2908 pSMB->Flags = 0;
2909 pSMB->Timeout = 0;
2910 pSMB->Reserved2 = 0;
2911 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002912 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 offset = param_offset + params;
2914
Steve French819f9162021-07-01 17:46:23 -05002915 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2916 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2918 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002919 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2920 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 name_len_target++; /* trailing null */
2922 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002923 } else {
2924 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 }
2926
2927 pSMB->MaxParameterCount = cpu_to_le16(2);
2928 /* BB find exact max on data count below from sess*/
2929 pSMB->MaxDataCount = cpu_to_le16(1000);
2930 pSMB->SetupCount = 1;
2931 pSMB->Reserved3 = 0;
2932 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2933 byte_count = 3 /* pad */ + params + name_len_target;
2934 pSMB->ParameterCount = cpu_to_le16(params);
2935 pSMB->TotalParameterCount = pSMB->ParameterCount;
2936 pSMB->DataCount = cpu_to_le16(name_len_target);
2937 pSMB->TotalDataCount = pSMB->DataCount;
2938 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2939 pSMB->DataOffset = cpu_to_le16(offset);
2940 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2941 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002942 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 pSMB->ByteCount = cpu_to_le16(byte_count);
2944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002946 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002947 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002948 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2949 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
2951 cifs_buf_release(pSMB);
2952 if (rc == -EAGAIN)
2953 goto createHardLinkRetry;
2954
2955 return rc;
2956}
2957
2958int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002959CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002960 const char *from_name, const char *to_name,
2961 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962{
2963 int rc = 0;
2964 NT_RENAME_REQ *pSMB = NULL;
2965 RENAME_RSP *pSMBr = NULL;
2966 int bytes_returned;
2967 int name_len, name_len2;
2968 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002969 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
Joe Perchesf96637b2013-05-04 22:12:25 -05002971 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972winCreateHardLinkRetry:
2973
2974 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2975 (void **) &pSMBr);
2976 if (rc)
2977 return rc;
2978
2979 pSMB->SearchAttributes =
2980 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2981 ATTR_DIRECTORY);
2982 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2983 pSMB->ClusterCount = 0;
2984
2985 pSMB->BufferFormat = 0x04;
2986
2987 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2988 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002989 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2990 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 name_len++; /* trailing null */
2992 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002993
2994 /* protocol specifies ASCII buffer format (0x04) for unicode */
2995 pSMB->OldFileName[name_len] = 0x04;
2996 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002998 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002999 to_name, PATH_MAX, cifs_sb->local_nls,
3000 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3002 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003003 } else {
3004 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003006 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 name_len2++; /* signature byte */
3008 }
3009
3010 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003011 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 pSMB->ByteCount = cpu_to_le16(count);
3013
3014 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3015 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003016 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003017 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003018 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003019
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 cifs_buf_release(pSMB);
3021 if (rc == -EAGAIN)
3022 goto winCreateHardLinkRetry;
3023
3024 return rc;
3025}
3026
3027int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003028CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003029 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003030 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031{
3032/* SMB_QUERY_FILE_UNIX_LINK */
3033 TRANSACTION2_QPI_REQ *pSMB = NULL;
3034 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3035 int rc = 0;
3036 int bytes_returned;
3037 int name_len;
3038 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003039 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
Joe Perchesf96637b2013-05-04 22:12:25 -05003041 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
3043querySymLinkRetry:
3044 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3045 (void **) &pSMBr);
3046 if (rc)
3047 return rc;
3048
3049 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3050 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003051 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3052 searchName, PATH_MAX, nls_codepage,
3053 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 name_len++; /* trailing null */
3055 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003056 } else {
3057 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 }
3059
3060 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3061 pSMB->TotalDataCount = 0;
3062 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003063 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 pSMB->MaxSetupCount = 0;
3065 pSMB->Reserved = 0;
3066 pSMB->Flags = 0;
3067 pSMB->Timeout = 0;
3068 pSMB->Reserved2 = 0;
3069 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003070 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 pSMB->DataCount = 0;
3072 pSMB->DataOffset = 0;
3073 pSMB->SetupCount = 1;
3074 pSMB->Reserved3 = 0;
3075 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3076 byte_count = params + 1 /* pad */ ;
3077 pSMB->TotalParameterCount = cpu_to_le16(params);
3078 pSMB->ParameterCount = pSMB->TotalParameterCount;
3079 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3080 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003081 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 pSMB->ByteCount = cpu_to_le16(byte_count);
3083
3084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3086 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003087 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 } else {
3089 /* decode response */
3090
3091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003093 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003094 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003096 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003097 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
Jeff Layton460b9692009-04-30 07:17:56 -04003099 data_start = ((char *) &pSMBr->hdr.Protocol) +
3100 le16_to_cpu(pSMBr->t2.DataOffset);
3101
Steve French0e0d2cf2009-05-01 05:27:32 +00003102 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3103 is_unicode = true;
3104 else
3105 is_unicode = false;
3106
Steve French737b7582005-04-28 22:41:06 -07003107 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003108 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3109 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003110 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003111 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 }
3113 }
3114 cifs_buf_release(pSMB);
3115 if (rc == -EAGAIN)
3116 goto querySymLinkRetry;
3117 return rc;
3118}
3119
Steve Frenchc52a95542011-02-24 06:16:22 +00003120/*
3121 * Recent Windows versions now create symlinks more frequently
3122 * and they use the "reparse point" mechanism below. We can of course
3123 * do symlinks nicely to Samba and other servers which support the
3124 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3125 * "MF" symlinks optionally, but for recent Windows we really need to
3126 * reenable the code below and fix the cifs_symlink callers to handle this.
3127 * In the interim this code has been moved to its own config option so
3128 * it is not compiled in by default until callers fixed up and more tested.
3129 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003131CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3132 __u16 fid, char **symlinkinfo,
3133 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134{
3135 int rc = 0;
3136 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003137 struct smb_com_transaction_ioctl_req *pSMB;
3138 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003139 bool is_unicode;
3140 unsigned int sub_len;
3141 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003142 struct reparse_symlink_data *reparse_buf;
3143 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003144 __u32 data_offset, data_count;
3145 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003147 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3149 (void **) &pSMBr);
3150 if (rc)
3151 return rc;
3152
3153 pSMB->TotalParameterCount = 0 ;
3154 pSMB->TotalDataCount = 0;
3155 pSMB->MaxParameterCount = cpu_to_le32(2);
3156 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003157 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 pSMB->MaxSetupCount = 4;
3159 pSMB->Reserved = 0;
3160 pSMB->ParameterOffset = 0;
3161 pSMB->DataCount = 0;
3162 pSMB->DataOffset = 0;
3163 pSMB->SetupCount = 4;
3164 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3165 pSMB->ParameterCount = pSMB->TotalParameterCount;
3166 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3167 pSMB->IsFsctl = 1; /* FSCTL */
3168 pSMB->IsRootFlag = 0;
3169 pSMB->Fid = fid; /* file handle always le */
3170 pSMB->ByteCount = 0;
3171
3172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3174 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003175 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003176 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 }
Steve French989c7e52009-05-02 05:32:20 +00003178
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003179 data_offset = le32_to_cpu(pSMBr->DataOffset);
3180 data_count = le32_to_cpu(pSMBr->DataCount);
3181 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3182 /* BB also check enough total bytes returned */
3183 rc = -EIO; /* bad smb */
3184 goto qreparse_out;
3185 }
3186 if (!data_count || (data_count > 2048)) {
3187 rc = -EIO;
3188 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3189 goto qreparse_out;
3190 }
3191 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003192 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003193 ((char *)&pSMBr->hdr.Protocol + data_offset);
3194 if ((char *)reparse_buf >= end_of_smb) {
3195 rc = -EIO;
3196 goto qreparse_out;
3197 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003198 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3199 cifs_dbg(FYI, "NFS style reparse tag\n");
3200 posix_buf = (struct reparse_posix_data *)reparse_buf;
3201
3202 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3203 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3204 le64_to_cpu(posix_buf->InodeType));
3205 rc = -EOPNOTSUPP;
3206 goto qreparse_out;
3207 }
3208 is_unicode = true;
3209 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3210 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3211 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3212 rc = -EIO;
3213 goto qreparse_out;
3214 }
3215 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3216 sub_len, is_unicode, nls_codepage);
3217 goto qreparse_out;
3218 } else if (reparse_buf->ReparseTag !=
3219 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3220 rc = -EOPNOTSUPP;
3221 goto qreparse_out;
3222 }
3223
3224 /* Reparse tag is NTFS symlink */
3225 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3226 reparse_buf->PathBuffer;
3227 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3228 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003229 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3230 rc = -EIO;
3231 goto qreparse_out;
3232 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003233 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3234 is_unicode = true;
3235 else
3236 is_unicode = false;
3237
3238 /* BB FIXME investigate remapping reserved chars here */
3239 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3240 nls_codepage);
3241 if (!*symlinkinfo)
3242 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003244 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003246 /*
3247 * Note: On -EAGAIN error only caller can retry on handle based calls
3248 * since file handle passed in no longer valid.
3249 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 return rc;
3251}
3252
Steve Frenchc7f508a2013-10-14 15:27:32 -05003253int
3254CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3255 __u16 fid)
3256{
3257 int rc = 0;
3258 int bytes_returned;
3259 struct smb_com_transaction_compr_ioctl_req *pSMB;
3260 struct smb_com_transaction_ioctl_rsp *pSMBr;
3261
3262 cifs_dbg(FYI, "Set compression for %u\n", fid);
3263 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3264 (void **) &pSMBr);
3265 if (rc)
3266 return rc;
3267
3268 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3269
3270 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003271 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003272 pSMB->MaxParameterCount = 0;
3273 pSMB->MaxDataCount = 0;
3274 pSMB->MaxSetupCount = 4;
3275 pSMB->Reserved = 0;
3276 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003277 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003278 pSMB->DataOffset =
3279 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3280 compression_state) - 4); /* 84 */
3281 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003282 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003283 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003284 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003285 pSMB->IsFsctl = 1; /* FSCTL */
3286 pSMB->IsRootFlag = 0;
3287 pSMB->Fid = fid; /* file handle always le */
3288 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003289 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003290 inc_rfc1001_len(pSMB, 5);
3291
3292 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3293 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3294 if (rc)
3295 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3296
3297 cifs_buf_release(pSMB);
3298
3299 /*
3300 * Note: On -EAGAIN error only caller can retry on handle based calls
3301 * since file handle passed in no longer valid.
3302 */
3303 return rc;
3304}
3305
3306
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307#ifdef CONFIG_CIFS_POSIX
3308
3309/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003310static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003311 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312{
3313 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003314 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3315 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3316 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003317/*
3318 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3319 ace->e_perm, ace->e_tag, ace->e_id);
3320*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
3322 return;
3323}
3324
3325/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003326static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3327 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328{
3329 int size = 0;
3330 int i;
3331 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003332 struct cifs_posix_ace *pACE;
3333 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003334 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335
3336 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3337 return -EOPNOTSUPP;
3338
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003339 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 count = le16_to_cpu(cifs_acl->access_entry_count);
3341 pACE = &cifs_acl->ace_array[0];
3342 size = sizeof(struct cifs_posix_acl);
3343 size += sizeof(struct cifs_posix_ace) * count;
3344 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003345 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003346 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3347 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 return -EINVAL;
3349 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003350 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 count = le16_to_cpu(cifs_acl->access_entry_count);
3352 size = sizeof(struct cifs_posix_acl);
3353 size += sizeof(struct cifs_posix_ace) * count;
3354/* skip past access ACEs to get to default ACEs */
3355 pACE = &cifs_acl->ace_array[count];
3356 count = le16_to_cpu(cifs_acl->default_entry_count);
3357 size += sizeof(struct cifs_posix_ace) * count;
3358 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003359 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 return -EINVAL;
3361 } else {
3362 /* illegal type */
3363 return -EINVAL;
3364 }
3365
3366 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003367 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003368 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003369 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 return -ERANGE;
3371 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003372 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3373
Steve Frenchff7feac2005-11-15 16:45:16 -08003374 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003375 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003376 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003377 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 }
3379 }
3380 return size;
3381}
3382
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303383static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003384 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385{
Steve Frenchff7feac2005-11-15 16:45:16 -08003386 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3387 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003389 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 /* Probably no need to le convert -1 on any arch but can not hurt */
3391 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003392 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003393 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003394/*
3395 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3396 ace->e_perm, ace->e_tag, ace->e_id);
3397*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398}
3399
3400/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003401static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3402 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403{
3404 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003405 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003406 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003407 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 int count;
3409 int i;
3410
Steve French790fe572007-07-07 19:25:05 +00003411 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 return 0;
3413
3414 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003415 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3416 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003417 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003418 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3419 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 return 0;
3421 }
3422 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003423 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003424 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003425 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003426 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003427 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003428 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003429 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003430 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 return 0;
3432 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303433 for (i = 0; i < count; i++)
3434 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003435 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3437 rc += sizeof(struct cifs_posix_acl);
3438 /* BB add check to make sure ACL does not overflow SMB */
3439 }
3440 return rc;
3441}
3442
3443int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003444CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003445 const unsigned char *searchName,
3446 char *acl_inf, const int buflen, const int acl_type,
3447 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
3449/* SMB_QUERY_POSIX_ACL */
3450 TRANSACTION2_QPI_REQ *pSMB = NULL;
3451 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3452 int rc = 0;
3453 int bytes_returned;
3454 int name_len;
3455 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003456
Joe Perchesf96637b2013-05-04 22:12:25 -05003457 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
3459queryAclRetry:
3460 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3461 (void **) &pSMBr);
3462 if (rc)
3463 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003464
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3466 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003467 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3468 searchName, PATH_MAX, nls_codepage,
3469 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 name_len++; /* trailing null */
3471 name_len *= 2;
3472 pSMB->FileName[name_len] = 0;
3473 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003474 } else {
3475 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 }
3477
3478 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3479 pSMB->TotalDataCount = 0;
3480 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003481 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 pSMB->MaxDataCount = cpu_to_le16(4000);
3483 pSMB->MaxSetupCount = 0;
3484 pSMB->Reserved = 0;
3485 pSMB->Flags = 0;
3486 pSMB->Timeout = 0;
3487 pSMB->Reserved2 = 0;
3488 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003489 offsetof(struct smb_com_transaction2_qpi_req,
3490 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 pSMB->DataCount = 0;
3492 pSMB->DataOffset = 0;
3493 pSMB->SetupCount = 1;
3494 pSMB->Reserved3 = 0;
3495 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3496 byte_count = params + 1 /* pad */ ;
3497 pSMB->TotalParameterCount = cpu_to_le16(params);
3498 pSMB->ParameterCount = pSMB->TotalParameterCount;
3499 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3500 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003501 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 pSMB->ByteCount = cpu_to_le16(byte_count);
3503
3504 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3505 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003506 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003508 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 } else {
3510 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003511
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003514 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 rc = -EIO; /* bad smb */
3516 else {
3517 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3518 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3519 rc = cifs_copy_posix_acl(acl_inf,
3520 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003521 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 }
3523 }
3524 cifs_buf_release(pSMB);
3525 if (rc == -EAGAIN)
3526 goto queryAclRetry;
3527 return rc;
3528}
3529
3530int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003531CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003532 const unsigned char *fileName,
3533 const char *local_acl, const int buflen,
3534 const int acl_type,
3535 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536{
3537 struct smb_com_transaction2_spi_req *pSMB = NULL;
3538 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3539 char *parm_data;
3540 int name_len;
3541 int rc = 0;
3542 int bytes_returned = 0;
3543 __u16 params, byte_count, data_count, param_offset, offset;
3544
Joe Perchesf96637b2013-05-04 22:12:25 -05003545 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546setAclRetry:
3547 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003548 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 if (rc)
3550 return rc;
3551 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3552 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003553 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3554 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 name_len++; /* trailing null */
3556 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003557 } else {
3558 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 }
3560 params = 6 + name_len;
3561 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003562 /* BB find max SMB size from sess */
3563 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 pSMB->MaxSetupCount = 0;
3565 pSMB->Reserved = 0;
3566 pSMB->Flags = 0;
3567 pSMB->Timeout = 0;
3568 pSMB->Reserved2 = 0;
3569 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003570 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 offset = param_offset + params;
3572 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3573 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3574
3575 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003576 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Steve French790fe572007-07-07 19:25:05 +00003578 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 rc = -EOPNOTSUPP;
3580 goto setACLerrorExit;
3581 }
3582 pSMB->DataOffset = cpu_to_le16(offset);
3583 pSMB->SetupCount = 1;
3584 pSMB->Reserved3 = 0;
3585 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3586 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3587 byte_count = 3 /* pad */ + params + data_count;
3588 pSMB->DataCount = cpu_to_le16(data_count);
3589 pSMB->TotalDataCount = pSMB->DataCount;
3590 pSMB->ParameterCount = cpu_to_le16(params);
3591 pSMB->TotalParameterCount = pSMB->ParameterCount;
3592 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003593 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 pSMB->ByteCount = cpu_to_le16(byte_count);
3595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003597 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003598 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600setACLerrorExit:
3601 cifs_buf_release(pSMB);
3602 if (rc == -EAGAIN)
3603 goto setAclRetry;
3604 return rc;
3605}
3606
Steve Frenchf654bac2005-04-28 22:41:04 -07003607/* BB fix tabs in this function FIXME BB */
3608int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003609CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003610 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003611{
Steve French50c2f752007-07-13 00:33:32 +00003612 int rc = 0;
3613 struct smb_t2_qfi_req *pSMB = NULL;
3614 struct smb_t2_qfi_rsp *pSMBr = NULL;
3615 int bytes_returned;
3616 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003617
Joe Perchesf96637b2013-05-04 22:12:25 -05003618 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003619 if (tcon == NULL)
3620 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003621
3622GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003623 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3624 (void **) &pSMBr);
3625 if (rc)
3626 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003627
Steve Frenchad7a2922008-02-07 23:25:02 +00003628 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003629 pSMB->t2.TotalDataCount = 0;
3630 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3631 /* BB find exact max data count below from sess structure BB */
3632 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3633 pSMB->t2.MaxSetupCount = 0;
3634 pSMB->t2.Reserved = 0;
3635 pSMB->t2.Flags = 0;
3636 pSMB->t2.Timeout = 0;
3637 pSMB->t2.Reserved2 = 0;
3638 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3639 Fid) - 4);
3640 pSMB->t2.DataCount = 0;
3641 pSMB->t2.DataOffset = 0;
3642 pSMB->t2.SetupCount = 1;
3643 pSMB->t2.Reserved3 = 0;
3644 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3645 byte_count = params + 1 /* pad */ ;
3646 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3647 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3648 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3649 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003650 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003651 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003652 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003653
Steve French790fe572007-07-07 19:25:05 +00003654 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3655 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3656 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003657 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003658 } else {
3659 /* decode response */
3660 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003661 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003662 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003663 /* If rc should we check for EOPNOSUPP and
3664 disable the srvino flag? or in caller? */
3665 rc = -EIO; /* bad smb */
3666 else {
3667 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3668 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3669 struct file_chattr_info *pfinfo;
3670 /* BB Do we need a cast or hash here ? */
3671 if (count != 16) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003672 cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003673 rc = -EIO;
3674 goto GetExtAttrOut;
3675 }
3676 pfinfo = (struct file_chattr_info *)
3677 (data_offset + (char *) &pSMBr->hdr.Protocol);
3678 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003679 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003680 }
3681 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003682GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003683 cifs_buf_release(pSMB);
3684 if (rc == -EAGAIN)
3685 goto GetExtAttrRetry;
3686 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003687}
3688
Steve Frenchf654bac2005-04-28 22:41:04 -07003689#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
Jeff Layton79df1ba2010-12-06 12:52:08 -05003691/*
3692 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3693 * all NT TRANSACTS that we init here have total parm and data under about 400
3694 * bytes (to fit in small cifs buffer size), which is the case so far, it
3695 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3696 * returned setup area) and MaxParameterCount (returned parms size) must be set
3697 * by caller
3698 */
3699static int
3700smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003701 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003702 void **ret_buf)
3703{
3704 int rc;
3705 __u32 temp_offset;
3706 struct smb_com_ntransact_req *pSMB;
3707
3708 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3709 (void **)&pSMB);
3710 if (rc)
3711 return rc;
3712 *ret_buf = (void *)pSMB;
3713 pSMB->Reserved = 0;
3714 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3715 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003716 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003717 pSMB->ParameterCount = pSMB->TotalParameterCount;
3718 pSMB->DataCount = pSMB->TotalDataCount;
3719 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3720 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3721 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3722 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3723 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3724 pSMB->SubCommand = cpu_to_le16(sub_command);
3725 return 0;
3726}
3727
3728static int
3729validate_ntransact(char *buf, char **ppparm, char **ppdata,
3730 __u32 *pparmlen, __u32 *pdatalen)
3731{
3732 char *end_of_smb;
3733 __u32 data_count, data_offset, parm_count, parm_offset;
3734 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003735 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003736
3737 *pdatalen = 0;
3738 *pparmlen = 0;
3739
3740 if (buf == NULL)
3741 return -EINVAL;
3742
3743 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3744
Jeff Layton820a8032011-05-04 08:05:26 -04003745 bcc = get_bcc(&pSMBr->hdr);
3746 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003747 (char *)&pSMBr->ByteCount;
3748
3749 data_offset = le32_to_cpu(pSMBr->DataOffset);
3750 data_count = le32_to_cpu(pSMBr->DataCount);
3751 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3752 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3753
3754 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3755 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3756
3757 /* should we also check that parm and data areas do not overlap? */
3758 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003759 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003760 return -EINVAL;
3761 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003762 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003763 return -EINVAL;
3764 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003765 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003766 return -EINVAL;
3767 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003768 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3769 *ppdata, data_count, (data_count + *ppdata),
3770 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003771 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003772 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003773 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003774 return -EINVAL;
3775 }
3776 *pdatalen = data_count;
3777 *pparmlen = parm_count;
3778 return 0;
3779}
3780
Steve French0a4b92c2006-01-12 15:44:21 -08003781/* Get Security Descriptor (by handle) from remote server for a file or dir */
3782int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003783CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003784 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003785{
3786 int rc = 0;
3787 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003788 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003789 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003790 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003791
Joe Perchesf96637b2013-05-04 22:12:25 -05003792 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003793
Steve French630f3f0c2007-10-25 21:17:17 +00003794 *pbuflen = 0;
3795 *acl_inf = NULL;
3796
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003797 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003798 8 /* parm len */, tcon, (void **) &pSMB);
3799 if (rc)
3800 return rc;
3801
3802 pSMB->MaxParameterCount = cpu_to_le32(4);
3803 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3804 pSMB->MaxSetupCount = 0;
3805 pSMB->Fid = fid; /* file handle always le */
3806 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3807 CIFS_ACL_DACL);
3808 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003809 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003810 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003811 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003812
Steve Frencha761ac52007-10-18 21:45:27 +00003813 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003814 0, &rsp_iov);
3815 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003816 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003817 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003818 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003819 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003820 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003821 __u32 parm_len;
3822 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003823 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003824 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003825
3826/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003827 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003828 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003829 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003830 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003831 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003832
Joe Perchesf96637b2013-05-04 22:12:25 -05003833 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3834 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003835
3836 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3837 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003838 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003839 goto qsec_out;
3840 }
3841
3842/* BB check that data area is minimum length and as big as acl_len */
3843
Steve Frenchaf6f4612007-10-16 18:40:37 +00003844 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003845 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003846 cifs_dbg(VFS, "acl length %d does not match %d\n",
3847 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003848 if (*pbuflen > acl_len)
3849 *pbuflen = acl_len;
3850 }
Steve French0a4b92c2006-01-12 15:44:21 -08003851
Steve French630f3f0c2007-10-25 21:17:17 +00003852 /* check if buffer is big enough for the acl
3853 header followed by the smallest SID */
3854 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3855 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003856 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003857 rc = -EINVAL;
3858 *pbuflen = 0;
3859 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003860 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003861 if (*acl_inf == NULL) {
3862 *pbuflen = 0;
3863 rc = -ENOMEM;
3864 }
Steve French630f3f0c2007-10-25 21:17:17 +00003865 }
Steve French0a4b92c2006-01-12 15:44:21 -08003866 }
3867qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003868 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003869 return rc;
3870}
Steve French97837582007-12-31 07:47:21 +00003871
3872int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003873CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003874 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003875{
3876 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3877 int rc = 0;
3878 int bytes_returned = 0;
3879 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003880 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003881
3882setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003883 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003884 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003885 return rc;
Steve French97837582007-12-31 07:47:21 +00003886
3887 pSMB->MaxSetupCount = 0;
3888 pSMB->Reserved = 0;
3889
3890 param_count = 8;
3891 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3892 data_count = acllen;
3893 data_offset = param_offset + param_count;
3894 byte_count = 3 /* pad */ + param_count;
3895
3896 pSMB->DataCount = cpu_to_le32(data_count);
3897 pSMB->TotalDataCount = pSMB->DataCount;
3898 pSMB->MaxParameterCount = cpu_to_le32(4);
3899 pSMB->MaxDataCount = cpu_to_le32(16384);
3900 pSMB->ParameterCount = cpu_to_le32(param_count);
3901 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3902 pSMB->TotalParameterCount = pSMB->ParameterCount;
3903 pSMB->DataOffset = cpu_to_le32(data_offset);
3904 pSMB->SetupCount = 0;
3905 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3906 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3907
3908 pSMB->Fid = fid; /* file handle always le */
3909 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003910 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003911
3912 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003913 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3914 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003915 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003916 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003917 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003918
3919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3921
Joe Perchesf96637b2013-05-04 22:12:25 -05003922 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3923 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003924 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003925 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003926 cifs_buf_release(pSMB);
3927
3928 if (rc == -EAGAIN)
3929 goto setCifsAclRetry;
3930
3931 return (rc);
3932}
3933
Steve French0a4b92c2006-01-12 15:44:21 -08003934
Steve French6b8edfe2005-08-23 20:26:03 -07003935/* Legacy Query Path Information call for lookup to old servers such
3936 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003937int
3938SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3939 const char *search_name, FILE_ALL_INFO *data,
3940 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003941{
Steve Frenchad7a2922008-02-07 23:25:02 +00003942 QUERY_INFORMATION_REQ *pSMB;
3943 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003944 int rc = 0;
3945 int bytes_returned;
3946 int name_len;
3947
Joe Perchesf96637b2013-05-04 22:12:25 -05003948 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003949QInfRetry:
3950 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003951 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003952 if (rc)
3953 return rc;
3954
3955 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3956 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003957 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003958 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003959 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003960 name_len++; /* trailing null */
3961 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003962 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003963 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003964 }
3965 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003966 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003967 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003968 pSMB->ByteCount = cpu_to_le16(name_len);
3969
3970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003971 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003972 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003973 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003974 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02003975 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00003976 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003977
3978 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003979 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003980 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003981 ts.tv_nsec = 0;
3982 ts.tv_sec = time;
3983 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003984 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3985 data->LastWriteTime = data->ChangeTime;
3986 data->LastAccessTime = 0;
3987 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003988 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003989 data->EndOfFile = data->AllocationSize;
3990 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003991 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003992 } else
3993 rc = -EIO; /* bad buffer passed in */
3994
3995 cifs_buf_release(pSMB);
3996
3997 if (rc == -EAGAIN)
3998 goto QInfRetry;
3999
4000 return rc;
4001}
4002
Jeff Laytonbcd53572010-02-12 07:44:16 -05004003int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004004CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004005 u16 netfid, FILE_ALL_INFO *pFindData)
4006{
4007 struct smb_t2_qfi_req *pSMB = NULL;
4008 struct smb_t2_qfi_rsp *pSMBr = NULL;
4009 int rc = 0;
4010 int bytes_returned;
4011 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004012
Jeff Laytonbcd53572010-02-12 07:44:16 -05004013QFileInfoRetry:
4014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4015 (void **) &pSMBr);
4016 if (rc)
4017 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004018
Jeff Laytonbcd53572010-02-12 07:44:16 -05004019 params = 2 /* level */ + 2 /* fid */;
4020 pSMB->t2.TotalDataCount = 0;
4021 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4022 /* BB find exact max data count below from sess structure BB */
4023 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4024 pSMB->t2.MaxSetupCount = 0;
4025 pSMB->t2.Reserved = 0;
4026 pSMB->t2.Flags = 0;
4027 pSMB->t2.Timeout = 0;
4028 pSMB->t2.Reserved2 = 0;
4029 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4030 Fid) - 4);
4031 pSMB->t2.DataCount = 0;
4032 pSMB->t2.DataOffset = 0;
4033 pSMB->t2.SetupCount = 1;
4034 pSMB->t2.Reserved3 = 0;
4035 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4036 byte_count = params + 1 /* pad */ ;
4037 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4038 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4039 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4040 pSMB->Pad = 0;
4041 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004042 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004043 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004044
4045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4047 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004048 cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004049 } else { /* decode response */
4050 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4051
4052 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4053 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004054 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004055 rc = -EIO; /* bad smb */
4056 else if (pFindData) {
4057 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4058 memcpy((char *) pFindData,
4059 (char *) &pSMBr->hdr.Protocol +
4060 data_offset, sizeof(FILE_ALL_INFO));
4061 } else
4062 rc = -ENOMEM;
4063 }
4064 cifs_buf_release(pSMB);
4065 if (rc == -EAGAIN)
4066 goto QFileInfoRetry;
4067
4068 return rc;
4069}
Steve French6b8edfe2005-08-23 20:26:03 -07004070
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004072CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004074 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004075 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004077 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 TRANSACTION2_QPI_REQ *pSMB = NULL;
4079 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4080 int rc = 0;
4081 int bytes_returned;
4082 int name_len;
4083 __u16 params, byte_count;
4084
Joe Perchesf96637b2013-05-04 22:12:25 -05004085 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086QPathInfoRetry:
4087 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4088 (void **) &pSMBr);
4089 if (rc)
4090 return rc;
4091
4092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4093 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004094 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004095 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 name_len++; /* trailing null */
4097 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004098 } else {
4099 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 }
4101
Steve French50c2f752007-07-13 00:33:32 +00004102 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 pSMB->TotalDataCount = 0;
4104 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004105 /* BB find exact max SMB PDU from sess structure BB */
4106 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 pSMB->MaxSetupCount = 0;
4108 pSMB->Reserved = 0;
4109 pSMB->Flags = 0;
4110 pSMB->Timeout = 0;
4111 pSMB->Reserved2 = 0;
4112 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004113 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 pSMB->DataCount = 0;
4115 pSMB->DataOffset = 0;
4116 pSMB->SetupCount = 1;
4117 pSMB->Reserved3 = 0;
4118 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4119 byte_count = params + 1 /* pad */ ;
4120 pSMB->TotalParameterCount = cpu_to_le16(params);
4121 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004122 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004123 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4124 else
4125 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004127 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 pSMB->ByteCount = cpu_to_le16(byte_count);
4129
4130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4132 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004133 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 } else { /* decode response */
4135 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4136
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004137 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4138 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004139 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004141 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004142 rc = -EIO; /* 24 or 26 expected but we do not read
4143 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004144 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004145 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004147
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004148 /*
4149 * On legacy responses we do not read the last field,
4150 * EAsize, fortunately since it varies by subdialect and
4151 * also note it differs on Set vs Get, ie two bytes or 4
4152 * bytes depending but we don't care here.
4153 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004154 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004155 size = sizeof(FILE_INFO_STANDARD);
4156 else
4157 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004158 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004159 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 } else
4161 rc = -ENOMEM;
4162 }
4163 cifs_buf_release(pSMB);
4164 if (rc == -EAGAIN)
4165 goto QPathInfoRetry;
4166
4167 return rc;
4168}
4169
4170int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004171CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004172 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4173{
4174 struct smb_t2_qfi_req *pSMB = NULL;
4175 struct smb_t2_qfi_rsp *pSMBr = NULL;
4176 int rc = 0;
4177 int bytes_returned;
4178 __u16 params, byte_count;
4179
4180UnixQFileInfoRetry:
4181 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4182 (void **) &pSMBr);
4183 if (rc)
4184 return rc;
4185
4186 params = 2 /* level */ + 2 /* fid */;
4187 pSMB->t2.TotalDataCount = 0;
4188 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4189 /* BB find exact max data count below from sess structure BB */
4190 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4191 pSMB->t2.MaxSetupCount = 0;
4192 pSMB->t2.Reserved = 0;
4193 pSMB->t2.Flags = 0;
4194 pSMB->t2.Timeout = 0;
4195 pSMB->t2.Reserved2 = 0;
4196 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4197 Fid) - 4);
4198 pSMB->t2.DataCount = 0;
4199 pSMB->t2.DataOffset = 0;
4200 pSMB->t2.SetupCount = 1;
4201 pSMB->t2.Reserved3 = 0;
4202 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4203 byte_count = params + 1 /* pad */ ;
4204 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4205 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4206 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4207 pSMB->Pad = 0;
4208 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004209 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004210 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004211
4212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4214 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004215 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004216 } else { /* decode response */
4217 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4218
Jeff Layton820a8032011-05-04 08:05:26 -04004219 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004220 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 -05004221 rc = -EIO; /* bad smb */
4222 } else {
4223 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4224 memcpy((char *) pFindData,
4225 (char *) &pSMBr->hdr.Protocol +
4226 data_offset,
4227 sizeof(FILE_UNIX_BASIC_INFO));
4228 }
4229 }
4230
4231 cifs_buf_release(pSMB);
4232 if (rc == -EAGAIN)
4233 goto UnixQFileInfoRetry;
4234
4235 return rc;
4236}
4237
4238int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004239CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004241 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004242 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243{
4244/* SMB_QUERY_FILE_UNIX_BASIC */
4245 TRANSACTION2_QPI_REQ *pSMB = NULL;
4246 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4247 int rc = 0;
4248 int bytes_returned = 0;
4249 int name_len;
4250 __u16 params, byte_count;
4251
Joe Perchesf96637b2013-05-04 22:12:25 -05004252 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253UnixQPathInfoRetry:
4254 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4255 (void **) &pSMBr);
4256 if (rc)
4257 return rc;
4258
4259 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4260 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004261 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4262 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 name_len++; /* trailing null */
4264 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004265 } else {
4266 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 }
4268
Steve French50c2f752007-07-13 00:33:32 +00004269 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 pSMB->TotalDataCount = 0;
4271 pSMB->MaxParameterCount = cpu_to_le16(2);
4272 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004273 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 pSMB->MaxSetupCount = 0;
4275 pSMB->Reserved = 0;
4276 pSMB->Flags = 0;
4277 pSMB->Timeout = 0;
4278 pSMB->Reserved2 = 0;
4279 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004280 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 pSMB->DataCount = 0;
4282 pSMB->DataOffset = 0;
4283 pSMB->SetupCount = 1;
4284 pSMB->Reserved3 = 0;
4285 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4286 byte_count = params + 1 /* pad */ ;
4287 pSMB->TotalParameterCount = cpu_to_le16(params);
4288 pSMB->ParameterCount = pSMB->TotalParameterCount;
4289 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4290 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004291 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 pSMB->ByteCount = cpu_to_le16(byte_count);
4293
4294 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4295 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4296 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004297 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 } else { /* decode response */
4299 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4300
Jeff Layton820a8032011-05-04 08:05:26 -04004301 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004302 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 -07004303 rc = -EIO; /* bad smb */
4304 } else {
4305 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4306 memcpy((char *) pFindData,
4307 (char *) &pSMBr->hdr.Protocol +
4308 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004309 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 }
4311 }
4312 cifs_buf_release(pSMB);
4313 if (rc == -EAGAIN)
4314 goto UnixQPathInfoRetry;
4315
4316 return rc;
4317}
4318
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319/* xid, tcon, searchName and codepage are input parms, rest are returned */
4320int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004321CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004322 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004323 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004324 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325{
4326/* level 257 SMB_ */
4327 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4328 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004329 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 int rc = 0;
4331 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004332 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004334 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335
Joe Perchesf96637b2013-05-04 22:12:25 -05004336 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337
4338findFirstRetry:
4339 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4340 (void **) &pSMBr);
4341 if (rc)
4342 return rc;
4343
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004344 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004345 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004346
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4348 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004349 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4350 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004351 /* We can not add the asterik earlier in case
4352 it got remapped to 0xF03A as if it were part of the
4353 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004355 if (msearch) {
4356 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4357 pSMB->FileName[name_len+1] = 0;
4358 pSMB->FileName[name_len+2] = '*';
4359 pSMB->FileName[name_len+3] = 0;
4360 name_len += 4; /* now the trailing null */
4361 /* null terminate just in case */
4362 pSMB->FileName[name_len] = 0;
4363 pSMB->FileName[name_len+1] = 0;
4364 name_len += 2;
4365 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004366 } else {
4367 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004368 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004369 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4370 name_len = PATH_MAX-2;
4371 /* overwrite nul byte */
4372 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4373 pSMB->FileName[name_len] = '*';
4374 pSMB->FileName[name_len+1] = 0;
4375 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 }
4378
4379 params = 12 + name_len /* includes null */ ;
4380 pSMB->TotalDataCount = 0; /* no EAs */
4381 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004382 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 pSMB->MaxSetupCount = 0;
4384 pSMB->Reserved = 0;
4385 pSMB->Flags = 0;
4386 pSMB->Timeout = 0;
4387 pSMB->Reserved2 = 0;
4388 byte_count = params + 1 /* pad */ ;
4389 pSMB->TotalParameterCount = cpu_to_le16(params);
4390 pSMB->ParameterCount = pSMB->TotalParameterCount;
4391 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004392 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4393 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 pSMB->DataCount = 0;
4395 pSMB->DataOffset = 0;
4396 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4397 pSMB->Reserved3 = 0;
4398 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4399 pSMB->SearchAttributes =
4400 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4401 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004402 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004403 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4405
4406 /* BB what should we set StorageType to? Does it matter? BB */
4407 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004408 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 pSMB->ByteCount = cpu_to_le16(byte_count);
4410
4411 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4412 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004413 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414
Steve French88274812006-03-09 22:21:45 +00004415 if (rc) {/* BB add logic to retry regular search if Unix search
4416 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004418 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004419
Steve French88274812006-03-09 22:21:45 +00004420 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
4422 /* BB eventually could optimize out free and realloc of buf */
4423 /* for this case */
4424 if (rc == -EAGAIN)
4425 goto findFirstRetry;
4426 } else { /* decode response */
4427 /* BB remember to free buffer if error BB */
4428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004429 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004430 unsigned int lnoff;
4431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004433 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 else
Steve French4b18f2a2008-04-29 00:06:05 +00004435 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436
4437 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
zhengbin01d1bd72019-12-25 11:30:21 +08004438 psrch_inf->smallBuf = false;
Steve French50c2f752007-07-13 00:33:32 +00004439 psrch_inf->srch_entries_start =
4440 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4443 le16_to_cpu(pSMBr->t2.ParameterOffset));
4444
Steve French790fe572007-07-07 19:25:05 +00004445 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004446 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 else
Steve French4b18f2a2008-04-29 00:06:05 +00004448 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
Steve French50c2f752007-07-13 00:33:32 +00004450 psrch_inf->entries_in_buffer =
4451 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004452 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004454 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004455 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004456 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004457 psrch_inf->last_entry = NULL;
4458 return rc;
4459 }
4460
Steve French0752f152008-10-07 20:03:33 +00004461 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004462 lnoff;
4463
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004464 if (pnetfid)
4465 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 } else {
4467 cifs_buf_release(pSMB);
4468 }
4469 }
4470
4471 return rc;
4472}
4473
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004474int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4475 __u16 searchHandle, __u16 search_flags,
4476 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477{
4478 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4479 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004480 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 char *response_data;
4482 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004483 int bytes_returned;
4484 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 __u16 params, byte_count;
4486
Joe Perchesf96637b2013-05-04 22:12:25 -05004487 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488
Steve French4b18f2a2008-04-29 00:06:05 +00004489 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 return -ENOENT;
4491
4492 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4493 (void **) &pSMBr);
4494 if (rc)
4495 return rc;
4496
Steve French50c2f752007-07-13 00:33:32 +00004497 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 byte_count = 0;
4499 pSMB->TotalDataCount = 0; /* no EAs */
4500 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004501 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 pSMB->MaxSetupCount = 0;
4503 pSMB->Reserved = 0;
4504 pSMB->Flags = 0;
4505 pSMB->Timeout = 0;
4506 pSMB->Reserved2 = 0;
4507 pSMB->ParameterOffset = cpu_to_le16(
4508 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4509 pSMB->DataCount = 0;
4510 pSMB->DataOffset = 0;
4511 pSMB->SetupCount = 1;
4512 pSMB->Reserved3 = 0;
4513 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4514 pSMB->SearchHandle = searchHandle; /* always kept as le */
4515 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004516 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4518 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004519 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
4521 name_len = psrch_inf->resume_name_len;
4522 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004523 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4525 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004526 /* 14 byte parm len above enough for 2 byte null terminator */
4527 pSMB->ResumeFileName[name_len] = 0;
4528 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 } else {
4530 rc = -EINVAL;
4531 goto FNext2_err_exit;
4532 }
4533 byte_count = params + 1 /* pad */ ;
4534 pSMB->TotalParameterCount = cpu_to_le16(params);
4535 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004536 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004538
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004541 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 if (rc) {
4543 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004544 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004545 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004546 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004548 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 } else { /* decode response */
4550 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004551
Steve French790fe572007-07-07 19:25:05 +00004552 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004553 unsigned int lnoff;
4554
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 /* BB fixme add lock for file (srch_info) struct here */
4556 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004557 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 else
Steve French4b18f2a2008-04-29 00:06:05 +00004559 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 response_data = (char *) &pSMBr->hdr.Protocol +
4561 le16_to_cpu(pSMBr->t2.ParameterOffset);
4562 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4563 response_data = (char *)&pSMBr->hdr.Protocol +
4564 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004565 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004566 cifs_small_buf_release(
4567 psrch_inf->ntwrk_buf_start);
4568 else
4569 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 psrch_inf->srch_entries_start = response_data;
4571 psrch_inf->ntwrk_buf_start = (char *)pSMB;
zhengbin01d1bd72019-12-25 11:30:21 +08004572 psrch_inf->smallBuf = false;
Steve French790fe572007-07-07 19:25:05 +00004573 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004574 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 else
Steve French4b18f2a2008-04-29 00:06:05 +00004576 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004577 psrch_inf->entries_in_buffer =
4578 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 psrch_inf->index_of_last_entry +=
4580 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004581 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004582 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004583 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004584 psrch_inf->last_entry = NULL;
4585 return rc;
4586 } else
4587 psrch_inf->last_entry =
4588 psrch_inf->srch_entries_start + lnoff;
4589
Joe Perchesf96637b2013-05-04 22:12:25 -05004590/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4591 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592
4593 /* BB fixme add unlock here */
4594 }
4595
4596 }
4597
4598 /* BB On error, should we leave previous search buf (and count and
4599 last entry fields) intact or free the previous one? */
4600
4601 /* Note: On -EAGAIN error only caller can retry on handle based calls
4602 since file handle passed in no longer valid */
4603FNext2_err_exit:
4604 if (rc != 0)
4605 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 return rc;
4607}
4608
4609int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004610CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004611 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612{
4613 int rc = 0;
4614 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615
Joe Perchesf96637b2013-05-04 22:12:25 -05004616 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4618
4619 /* no sense returning error if session restarted
4620 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004621 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 return 0;
4623 if (rc)
4624 return rc;
4625
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 pSMB->FileID = searchHandle;
4627 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004628 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004629 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004630 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004631 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004632
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004633 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634
4635 /* Since session is dead, search handle closed on server already */
4636 if (rc == -EAGAIN)
4637 rc = 0;
4638
4639 return rc;
4640}
4641
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004643CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004644 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004645 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646{
4647 int rc = 0;
4648 TRANSACTION2_QPI_REQ *pSMB = NULL;
4649 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4650 int name_len, bytes_returned;
4651 __u16 params, byte_count;
4652
Joe Perchesf96637b2013-05-04 22:12:25 -05004653 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004654 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004655 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656
4657GetInodeNumberRetry:
4658 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004659 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 if (rc)
4661 return rc;
4662
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4664 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004665 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004666 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004667 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 name_len++; /* trailing null */
4669 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004670 } else {
4671 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 }
4673
4674 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4675 pSMB->TotalDataCount = 0;
4676 pSMB->MaxParameterCount = cpu_to_le16(2);
4677 /* BB find exact max data count below from sess structure BB */
4678 pSMB->MaxDataCount = cpu_to_le16(4000);
4679 pSMB->MaxSetupCount = 0;
4680 pSMB->Reserved = 0;
4681 pSMB->Flags = 0;
4682 pSMB->Timeout = 0;
4683 pSMB->Reserved2 = 0;
4684 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004685 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 pSMB->DataCount = 0;
4687 pSMB->DataOffset = 0;
4688 pSMB->SetupCount = 1;
4689 pSMB->Reserved3 = 0;
4690 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4691 byte_count = params + 1 /* pad */ ;
4692 pSMB->TotalParameterCount = cpu_to_le16(params);
4693 pSMB->ParameterCount = pSMB->TotalParameterCount;
4694 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4695 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004696 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 pSMB->ByteCount = cpu_to_le16(byte_count);
4698
4699 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4700 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4701 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004702 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 } else {
4704 /* decode response */
4705 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004707 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 /* If rc should we check for EOPNOSUPP and
4709 disable the srvino flag? or in caller? */
4710 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004711 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4713 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004714 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004716 if (count < 8) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004717 cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 rc = -EIO;
4719 goto GetInodeNumOut;
4720 }
4721 pfinfo = (struct file_internal_info *)
4722 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004723 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 }
4725 }
4726GetInodeNumOut:
4727 cifs_buf_release(pSMB);
4728 if (rc == -EAGAIN)
4729 goto GetInodeNumberRetry;
4730 return rc;
4731}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
4733int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004734CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004735 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004736 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004737 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738{
4739/* TRANS2_GET_DFS_REFERRAL */
4740 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4741 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 int rc = 0;
4743 int bytes_returned;
4744 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004746 *num_of_nodes = 0;
4747 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
Joe Perchesf96637b2013-05-04 22:12:25 -05004749 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004750 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004752
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004754 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 (void **) &pSMBr);
4756 if (rc)
4757 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004758
4759 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004760 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004761 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004762 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004764 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004766 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
4769 if (ses->capabilities & CAP_UNICODE) {
4770 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4771 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004772 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004773 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004774 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 name_len++; /* trailing null */
4776 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004777 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004778 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 }
4780
Dan Carpenter65c3b202015-04-30 17:30:24 +03004781 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004782 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004783
Steve French50c2f752007-07-13 00:33:32 +00004784 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004785
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 params = 2 /* level */ + name_len /*includes null */ ;
4787 pSMB->TotalDataCount = 0;
4788 pSMB->DataCount = 0;
4789 pSMB->DataOffset = 0;
4790 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004791 /* BB find exact max SMB PDU from sess structure BB */
4792 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 pSMB->MaxSetupCount = 0;
4794 pSMB->Reserved = 0;
4795 pSMB->Flags = 0;
4796 pSMB->Timeout = 0;
4797 pSMB->Reserved2 = 0;
4798 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004799 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 pSMB->SetupCount = 1;
4801 pSMB->Reserved3 = 0;
4802 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4803 byte_count = params + 3 /* pad */ ;
4804 pSMB->ParameterCount = cpu_to_le16(params);
4805 pSMB->TotalParameterCount = pSMB->ParameterCount;
4806 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004807 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 pSMB->ByteCount = cpu_to_le16(byte_count);
4809
4810 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4812 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004813 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004814 goto GetDFSRefExit;
4815 }
4816 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004818 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004819 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004820 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004821 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004823
Joe Perchesf96637b2013-05-04 22:12:25 -05004824 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4825 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004826
4827 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004828 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4829 le16_to_cpu(pSMBr->t2.DataCount),
4830 num_of_nodes, target_nodes, nls_codepage,
4831 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004832 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004833
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004835 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
4837 if (rc == -EAGAIN)
4838 goto getDFSRetry;
4839
4840 return rc;
4841}
4842
Steve French20962432005-09-21 22:05:57 -07004843/* Query File System Info such as free space to old servers such as Win 9x */
4844int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004845SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4846 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004847{
4848/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4849 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4850 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4851 FILE_SYSTEM_ALLOC_INFO *response_data;
4852 int rc = 0;
4853 int bytes_returned = 0;
4854 __u16 params, byte_count;
4855
Joe Perchesf96637b2013-05-04 22:12:25 -05004856 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004857oldQFSInfoRetry:
4858 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4859 (void **) &pSMBr);
4860 if (rc)
4861 return rc;
Steve French20962432005-09-21 22:05:57 -07004862
4863 params = 2; /* level */
4864 pSMB->TotalDataCount = 0;
4865 pSMB->MaxParameterCount = cpu_to_le16(2);
4866 pSMB->MaxDataCount = cpu_to_le16(1000);
4867 pSMB->MaxSetupCount = 0;
4868 pSMB->Reserved = 0;
4869 pSMB->Flags = 0;
4870 pSMB->Timeout = 0;
4871 pSMB->Reserved2 = 0;
4872 byte_count = params + 1 /* pad */ ;
4873 pSMB->TotalParameterCount = cpu_to_le16(params);
4874 pSMB->ParameterCount = pSMB->TotalParameterCount;
4875 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4876 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4877 pSMB->DataCount = 0;
4878 pSMB->DataOffset = 0;
4879 pSMB->SetupCount = 1;
4880 pSMB->Reserved3 = 0;
4881 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4882 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004883 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004884 pSMB->ByteCount = cpu_to_le16(byte_count);
4885
4886 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4888 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004889 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004890 } else { /* decode response */
4891 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4892
Jeff Layton820a8032011-05-04 08:05:26 -04004893 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004894 rc = -EIO; /* bad smb */
4895 else {
4896 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004897 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004898 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004899
Steve French50c2f752007-07-13 00:33:32 +00004900 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004901 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4902 FSData->f_bsize =
4903 le16_to_cpu(response_data->BytesPerSector) *
4904 le32_to_cpu(response_data->
4905 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05004906 /*
4907 * much prefer larger but if server doesn't report
4908 * a valid size than 4K is a reasonable minimum
4909 */
4910 if (FSData->f_bsize < 512)
4911 FSData->f_bsize = 4096;
4912
Steve French20962432005-09-21 22:05:57 -07004913 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004914 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004915 FSData->f_bfree = FSData->f_bavail =
4916 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004917 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4918 (unsigned long long)FSData->f_blocks,
4919 (unsigned long long)FSData->f_bfree,
4920 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004921 }
4922 }
4923 cifs_buf_release(pSMB);
4924
4925 if (rc == -EAGAIN)
4926 goto oldQFSInfoRetry;
4927
4928 return rc;
4929}
4930
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004932CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4933 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934{
4935/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4936 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4937 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4938 FILE_SYSTEM_INFO *response_data;
4939 int rc = 0;
4940 int bytes_returned = 0;
4941 __u16 params, byte_count;
4942
Joe Perchesf96637b2013-05-04 22:12:25 -05004943 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944QFSInfoRetry:
4945 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4946 (void **) &pSMBr);
4947 if (rc)
4948 return rc;
4949
4950 params = 2; /* level */
4951 pSMB->TotalDataCount = 0;
4952 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004953 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 pSMB->MaxSetupCount = 0;
4955 pSMB->Reserved = 0;
4956 pSMB->Flags = 0;
4957 pSMB->Timeout = 0;
4958 pSMB->Reserved2 = 0;
4959 byte_count = params + 1 /* pad */ ;
4960 pSMB->TotalParameterCount = cpu_to_le16(params);
4961 pSMB->ParameterCount = pSMB->TotalParameterCount;
4962 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004963 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 pSMB->DataCount = 0;
4965 pSMB->DataOffset = 0;
4966 pSMB->SetupCount = 1;
4967 pSMB->Reserved3 = 0;
4968 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4969 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004970 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 pSMB->ByteCount = cpu_to_le16(byte_count);
4972
4973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4975 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004976 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004978 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979
Jeff Layton820a8032011-05-04 08:05:26 -04004980 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 rc = -EIO; /* bad smb */
4982 else {
4983 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
4985 response_data =
4986 (FILE_SYSTEM_INFO
4987 *) (((char *) &pSMBr->hdr.Protocol) +
4988 data_offset);
4989 FSData->f_bsize =
4990 le32_to_cpu(response_data->BytesPerSector) *
4991 le32_to_cpu(response_data->
4992 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05004993 /*
4994 * much prefer larger but if server doesn't report
4995 * a valid size than 4K is a reasonable minimum
4996 */
4997 if (FSData->f_bsize < 512)
4998 FSData->f_bsize = 4096;
4999
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 FSData->f_blocks =
5001 le64_to_cpu(response_data->TotalAllocationUnits);
5002 FSData->f_bfree = FSData->f_bavail =
5003 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005004 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5005 (unsigned long long)FSData->f_blocks,
5006 (unsigned long long)FSData->f_bfree,
5007 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 }
5009 }
5010 cifs_buf_release(pSMB);
5011
5012 if (rc == -EAGAIN)
5013 goto QFSInfoRetry;
5014
5015 return rc;
5016}
5017
5018int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005019CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020{
5021/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5022 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5023 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5024 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5025 int rc = 0;
5026 int bytes_returned = 0;
5027 __u16 params, byte_count;
5028
Joe Perchesf96637b2013-05-04 22:12:25 -05005029 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030QFSAttributeRetry:
5031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5032 (void **) &pSMBr);
5033 if (rc)
5034 return rc;
5035
5036 params = 2; /* level */
5037 pSMB->TotalDataCount = 0;
5038 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005039 /* BB find exact max SMB PDU from sess structure BB */
5040 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 pSMB->MaxSetupCount = 0;
5042 pSMB->Reserved = 0;
5043 pSMB->Flags = 0;
5044 pSMB->Timeout = 0;
5045 pSMB->Reserved2 = 0;
5046 byte_count = params + 1 /* pad */ ;
5047 pSMB->TotalParameterCount = cpu_to_le16(params);
5048 pSMB->ParameterCount = pSMB->TotalParameterCount;
5049 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005050 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 pSMB->DataCount = 0;
5052 pSMB->DataOffset = 0;
5053 pSMB->SetupCount = 1;
5054 pSMB->Reserved3 = 0;
5055 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5056 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005057 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 pSMB->ByteCount = cpu_to_le16(byte_count);
5059
5060 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5061 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5062 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005063 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 } else { /* decode response */
5065 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5066
Jeff Layton820a8032011-05-04 08:05:26 -04005067 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005068 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 rc = -EIO; /* bad smb */
5070 } else {
5071 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5072 response_data =
5073 (FILE_SYSTEM_ATTRIBUTE_INFO
5074 *) (((char *) &pSMBr->hdr.Protocol) +
5075 data_offset);
5076 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005077 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 }
5079 }
5080 cifs_buf_release(pSMB);
5081
5082 if (rc == -EAGAIN)
5083 goto QFSAttributeRetry;
5084
5085 return rc;
5086}
5087
5088int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005089CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090{
5091/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5092 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5093 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5094 FILE_SYSTEM_DEVICE_INFO *response_data;
5095 int rc = 0;
5096 int bytes_returned = 0;
5097 __u16 params, byte_count;
5098
Joe Perchesf96637b2013-05-04 22:12:25 -05005099 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100QFSDeviceRetry:
5101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5102 (void **) &pSMBr);
5103 if (rc)
5104 return rc;
5105
5106 params = 2; /* level */
5107 pSMB->TotalDataCount = 0;
5108 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005109 /* BB find exact max SMB PDU from sess structure BB */
5110 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 pSMB->MaxSetupCount = 0;
5112 pSMB->Reserved = 0;
5113 pSMB->Flags = 0;
5114 pSMB->Timeout = 0;
5115 pSMB->Reserved2 = 0;
5116 byte_count = params + 1 /* pad */ ;
5117 pSMB->TotalParameterCount = cpu_to_le16(params);
5118 pSMB->ParameterCount = pSMB->TotalParameterCount;
5119 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005120 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121
5122 pSMB->DataCount = 0;
5123 pSMB->DataOffset = 0;
5124 pSMB->SetupCount = 1;
5125 pSMB->Reserved3 = 0;
5126 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5127 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005128 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 pSMB->ByteCount = cpu_to_le16(byte_count);
5130
5131 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5132 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5133 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005134 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 } else { /* decode response */
5136 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5137
Jeff Layton820a8032011-05-04 08:05:26 -04005138 if (rc || get_bcc(&pSMBr->hdr) <
5139 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 rc = -EIO; /* bad smb */
5141 else {
5142 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5143 response_data =
Steve French737b7582005-04-28 22:41:06 -07005144 (FILE_SYSTEM_DEVICE_INFO *)
5145 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 data_offset);
5147 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005148 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 }
5150 }
5151 cifs_buf_release(pSMB);
5152
5153 if (rc == -EAGAIN)
5154 goto QFSDeviceRetry;
5155
5156 return rc;
5157}
5158
5159int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005160CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161{
5162/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5163 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5164 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5165 FILE_SYSTEM_UNIX_INFO *response_data;
5166 int rc = 0;
5167 int bytes_returned = 0;
5168 __u16 params, byte_count;
5169
Joe Perchesf96637b2013-05-04 22:12:25 -05005170 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005172 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5173 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 if (rc)
5175 return rc;
5176
5177 params = 2; /* level */
5178 pSMB->TotalDataCount = 0;
5179 pSMB->DataCount = 0;
5180 pSMB->DataOffset = 0;
5181 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005182 /* BB find exact max SMB PDU from sess structure BB */
5183 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 pSMB->MaxSetupCount = 0;
5185 pSMB->Reserved = 0;
5186 pSMB->Flags = 0;
5187 pSMB->Timeout = 0;
5188 pSMB->Reserved2 = 0;
5189 byte_count = params + 1 /* pad */ ;
5190 pSMB->ParameterCount = cpu_to_le16(params);
5191 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005192 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5193 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 pSMB->SetupCount = 1;
5195 pSMB->Reserved3 = 0;
5196 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5197 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005198 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 pSMB->ByteCount = cpu_to_le16(byte_count);
5200
5201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5203 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005204 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 } else { /* decode response */
5206 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5207
Jeff Layton820a8032011-05-04 08:05:26 -04005208 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 rc = -EIO; /* bad smb */
5210 } else {
5211 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5212 response_data =
5213 (FILE_SYSTEM_UNIX_INFO
5214 *) (((char *) &pSMBr->hdr.Protocol) +
5215 data_offset);
5216 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005217 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 }
5219 }
5220 cifs_buf_release(pSMB);
5221
5222 if (rc == -EAGAIN)
5223 goto QFSUnixRetry;
5224
5225
5226 return rc;
5227}
5228
Jeremy Allisonac670552005-06-22 17:26:35 -07005229int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005230CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005231{
5232/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5233 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5234 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5235 int rc = 0;
5236 int bytes_returned = 0;
5237 __u16 params, param_offset, offset, byte_count;
5238
Joe Perchesf96637b2013-05-04 22:12:25 -05005239 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005240SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005241 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005242 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5243 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005244 if (rc)
5245 return rc;
5246
5247 params = 4; /* 2 bytes zero followed by info level. */
5248 pSMB->MaxSetupCount = 0;
5249 pSMB->Reserved = 0;
5250 pSMB->Flags = 0;
5251 pSMB->Timeout = 0;
5252 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005253 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5254 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005255 offset = param_offset + params;
5256
5257 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005258 /* BB find exact max SMB PDU from sess structure BB */
5259 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005260 pSMB->SetupCount = 1;
5261 pSMB->Reserved3 = 0;
5262 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5263 byte_count = 1 /* pad */ + params + 12;
5264
5265 pSMB->DataCount = cpu_to_le16(12);
5266 pSMB->ParameterCount = cpu_to_le16(params);
5267 pSMB->TotalDataCount = pSMB->DataCount;
5268 pSMB->TotalParameterCount = pSMB->ParameterCount;
5269 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5270 pSMB->DataOffset = cpu_to_le16(offset);
5271
5272 /* Params. */
5273 pSMB->FileNum = 0;
5274 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5275
5276 /* Data. */
5277 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5278 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5279 pSMB->ClientUnixCap = cpu_to_le64(cap);
5280
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005281 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005282 pSMB->ByteCount = cpu_to_le16(byte_count);
5283
5284 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5285 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5286 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005287 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005288 } else { /* decode response */
5289 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005290 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005291 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005292 }
5293 cifs_buf_release(pSMB);
5294
5295 if (rc == -EAGAIN)
5296 goto SETFSUnixRetry;
5297
5298 return rc;
5299}
5300
5301
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302
5303int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005304CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005305 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306{
5307/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5308 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5309 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5310 FILE_SYSTEM_POSIX_INFO *response_data;
5311 int rc = 0;
5312 int bytes_returned = 0;
5313 __u16 params, byte_count;
5314
Joe Perchesf96637b2013-05-04 22:12:25 -05005315 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316QFSPosixRetry:
5317 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5318 (void **) &pSMBr);
5319 if (rc)
5320 return rc;
5321
5322 params = 2; /* level */
5323 pSMB->TotalDataCount = 0;
5324 pSMB->DataCount = 0;
5325 pSMB->DataOffset = 0;
5326 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005327 /* BB find exact max SMB PDU from sess structure BB */
5328 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 pSMB->MaxSetupCount = 0;
5330 pSMB->Reserved = 0;
5331 pSMB->Flags = 0;
5332 pSMB->Timeout = 0;
5333 pSMB->Reserved2 = 0;
5334 byte_count = params + 1 /* pad */ ;
5335 pSMB->ParameterCount = cpu_to_le16(params);
5336 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005337 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5338 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339 pSMB->SetupCount = 1;
5340 pSMB->Reserved3 = 0;
5341 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5342 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005343 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 pSMB->ByteCount = cpu_to_le16(byte_count);
5345
5346 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5347 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5348 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005349 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 } else { /* decode response */
5351 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5352
Jeff Layton820a8032011-05-04 08:05:26 -04005353 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 rc = -EIO; /* bad smb */
5355 } else {
5356 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5357 response_data =
5358 (FILE_SYSTEM_POSIX_INFO
5359 *) (((char *) &pSMBr->hdr.Protocol) +
5360 data_offset);
5361 FSData->f_bsize =
5362 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005363 /*
5364 * much prefer larger but if server doesn't report
5365 * a valid size than 4K is a reasonable minimum
5366 */
5367 if (FSData->f_bsize < 512)
5368 FSData->f_bsize = 4096;
5369
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 FSData->f_blocks =
5371 le64_to_cpu(response_data->TotalBlocks);
5372 FSData->f_bfree =
5373 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005374 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 FSData->f_bavail = FSData->f_bfree;
5376 } else {
5377 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005378 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 }
Steve French790fe572007-07-07 19:25:05 +00005380 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005382 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005383 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005385 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 }
5387 }
5388 cifs_buf_release(pSMB);
5389
5390 if (rc == -EAGAIN)
5391 goto QFSPosixRetry;
5392
5393 return rc;
5394}
5395
5396
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005397/*
5398 * We can not use write of zero bytes trick to set file size due to need for
5399 * large file support. Also note that this SetPathInfo is preferred to
5400 * SetFileInfo based method in next routine which is only needed to work around
5401 * a sharing violation bugin Samba which this routine can run into.
5402 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005404CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005405 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5406 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407{
5408 struct smb_com_transaction2_spi_req *pSMB = NULL;
5409 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5410 struct file_end_of_file_info *parm_data;
5411 int name_len;
5412 int rc = 0;
5413 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005414 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005415
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 __u16 params, byte_count, data_count, param_offset, offset;
5417
Joe Perchesf96637b2013-05-04 22:12:25 -05005418 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419SetEOFRetry:
5420 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5421 (void **) &pSMBr);
5422 if (rc)
5423 return rc;
5424
5425 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5426 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005427 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5428 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 name_len++; /* trailing null */
5430 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005431 } else {
5432 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 }
5434 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005435 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005437 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 pSMB->MaxSetupCount = 0;
5439 pSMB->Reserved = 0;
5440 pSMB->Flags = 0;
5441 pSMB->Timeout = 0;
5442 pSMB->Reserved2 = 0;
5443 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005444 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005446 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005447 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5448 pSMB->InformationLevel =
5449 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5450 else
5451 pSMB->InformationLevel =
5452 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5453 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5455 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005456 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 else
5458 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005459 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 }
5461
5462 parm_data =
5463 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5464 offset);
5465 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5466 pSMB->DataOffset = cpu_to_le16(offset);
5467 pSMB->SetupCount = 1;
5468 pSMB->Reserved3 = 0;
5469 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5470 byte_count = 3 /* pad */ + params + data_count;
5471 pSMB->DataCount = cpu_to_le16(data_count);
5472 pSMB->TotalDataCount = pSMB->DataCount;
5473 pSMB->ParameterCount = cpu_to_le16(params);
5474 pSMB->TotalParameterCount = pSMB->ParameterCount;
5475 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005476 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 parm_data->FileSize = cpu_to_le64(size);
5478 pSMB->ByteCount = cpu_to_le16(byte_count);
5479 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5480 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005481 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005482 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
5484 cifs_buf_release(pSMB);
5485
5486 if (rc == -EAGAIN)
5487 goto SetEOFRetry;
5488
5489 return rc;
5490}
5491
5492int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005493CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5494 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495{
5496 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 struct file_end_of_file_info *parm_data;
5498 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 __u16 params, param_offset, offset, byte_count, count;
5500
Joe Perchesf96637b2013-05-04 22:12:25 -05005501 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5502 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005503 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5504
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 if (rc)
5506 return rc;
5507
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005508 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5509 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005510
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 params = 6;
5512 pSMB->MaxSetupCount = 0;
5513 pSMB->Reserved = 0;
5514 pSMB->Flags = 0;
5515 pSMB->Timeout = 0;
5516 pSMB->Reserved2 = 0;
5517 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5518 offset = param_offset + params;
5519
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 count = sizeof(struct file_end_of_file_info);
5521 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005522 /* BB find exact max SMB PDU from sess structure BB */
5523 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 pSMB->SetupCount = 1;
5525 pSMB->Reserved3 = 0;
5526 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5527 byte_count = 3 /* pad */ + params + count;
5528 pSMB->DataCount = cpu_to_le16(count);
5529 pSMB->ParameterCount = cpu_to_le16(params);
5530 pSMB->TotalDataCount = pSMB->DataCount;
5531 pSMB->TotalParameterCount = pSMB->ParameterCount;
5532 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve Frenche3973ea2021-07-06 21:27:26 -05005533 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 parm_data =
Steve Frenche3973ea2021-07-06 21:27:26 -05005535 (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 pSMB->DataOffset = cpu_to_le16(offset);
5537 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005538 pSMB->Fid = cfile->fid.netfid;
5539 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5541 pSMB->InformationLevel =
5542 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5543 else
5544 pSMB->InformationLevel =
5545 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005546 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5548 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005549 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 else
5551 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005552 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 }
5554 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005555 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005557 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005558 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005560 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5561 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 }
5563
Steve French50c2f752007-07-13 00:33:32 +00005564 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 since file handle passed in no longer valid */
5566
5567 return rc;
5568}
5569
Steve French50c2f752007-07-13 00:33:32 +00005570/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 an open handle, rather than by pathname - this is awkward due to
5572 potential access conflicts on the open, but it is unavoidable for these
5573 old servers since the only other choice is to go from 100 nanosecond DCE
5574 time and resort to the original setpathinfo level which takes the ancient
5575 DOS time format with 2 second granularity */
5576int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005577CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005578 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579{
5580 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 char *data_offset;
5582 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 __u16 params, param_offset, offset, byte_count, count;
5584
Joe Perchesf96637b2013-05-04 22:12:25 -05005585 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005586 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5587
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 if (rc)
5589 return rc;
5590
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005591 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5592 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005593
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 params = 6;
5595 pSMB->MaxSetupCount = 0;
5596 pSMB->Reserved = 0;
5597 pSMB->Flags = 0;
5598 pSMB->Timeout = 0;
5599 pSMB->Reserved2 = 0;
5600 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5601 offset = param_offset + params;
5602
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005603 data_offset = (char *)pSMB +
5604 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605
Steve French26f57362007-08-30 22:09:15 +00005606 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005608 /* BB find max SMB PDU from sess */
5609 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 pSMB->SetupCount = 1;
5611 pSMB->Reserved3 = 0;
5612 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5613 byte_count = 3 /* pad */ + params + count;
5614 pSMB->DataCount = cpu_to_le16(count);
5615 pSMB->ParameterCount = cpu_to_le16(params);
5616 pSMB->TotalDataCount = pSMB->DataCount;
5617 pSMB->TotalParameterCount = pSMB->ParameterCount;
5618 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5619 pSMB->DataOffset = cpu_to_le16(offset);
5620 pSMB->Fid = fid;
5621 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5622 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5623 else
5624 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5625 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005626 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005628 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005629 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005630 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005631 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005632 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5633 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634
Steve French50c2f752007-07-13 00:33:32 +00005635 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 since file handle passed in no longer valid */
5637
5638 return rc;
5639}
5640
Jeff Layton6d22f092008-09-23 11:48:35 -04005641int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005642CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005643 bool delete_file, __u16 fid, __u32 pid_of_opener)
5644{
5645 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5646 char *data_offset;
5647 int rc = 0;
5648 __u16 params, param_offset, offset, byte_count, count;
5649
Joe Perchesf96637b2013-05-04 22:12:25 -05005650 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005651 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5652
5653 if (rc)
5654 return rc;
5655
5656 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5657 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5658
5659 params = 6;
5660 pSMB->MaxSetupCount = 0;
5661 pSMB->Reserved = 0;
5662 pSMB->Flags = 0;
5663 pSMB->Timeout = 0;
5664 pSMB->Reserved2 = 0;
5665 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5666 offset = param_offset + params;
5667
Steve French2a780e82021-07-06 21:42:08 -05005668 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
5669 data_offset = (char *)(pSMB) + offset + 4;
Jeff Layton6d22f092008-09-23 11:48:35 -04005670
5671 count = 1;
5672 pSMB->MaxParameterCount = cpu_to_le16(2);
5673 /* BB find max SMB PDU from sess */
5674 pSMB->MaxDataCount = cpu_to_le16(1000);
5675 pSMB->SetupCount = 1;
5676 pSMB->Reserved3 = 0;
5677 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5678 byte_count = 3 /* pad */ + params + count;
5679 pSMB->DataCount = cpu_to_le16(count);
5680 pSMB->ParameterCount = cpu_to_le16(params);
5681 pSMB->TotalDataCount = pSMB->DataCount;
5682 pSMB->TotalParameterCount = pSMB->ParameterCount;
5683 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5684 pSMB->DataOffset = cpu_to_le16(offset);
5685 pSMB->Fid = fid;
5686 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5687 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005688 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005689 pSMB->ByteCount = cpu_to_le16(byte_count);
5690 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005691 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005692 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005693 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005694 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005695
5696 return rc;
5697}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005699static int
5700CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
5701 const char *fileName, const FILE_BASIC_INFO *data,
5702 const struct nls_table *nls_codepage,
5703 struct cifs_sb_info *cifs_sb)
5704{
5705 int oplock = 0;
5706 struct cifs_open_parms oparms;
5707 struct cifs_fid fid;
5708 int rc;
5709
5710 oparms.tcon = tcon;
5711 oparms.cifs_sb = cifs_sb;
5712 oparms.desired_access = GENERIC_WRITE;
5713 oparms.create_options = cifs_create_options(cifs_sb, 0);
5714 oparms.disposition = FILE_OPEN;
5715 oparms.path = fileName;
5716 oparms.fid = &fid;
5717 oparms.reconnect = false;
5718
5719 rc = CIFS_open(xid, &oparms, &oplock, NULL);
5720 if (rc)
5721 goto out;
5722
5723 rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
5724 CIFSSMBClose(xid, tcon, fid.netfid);
5725out:
5726
5727 return rc;
5728}
5729
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005731CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005732 const char *fileName, const FILE_BASIC_INFO *data,
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005733 const struct nls_table *nls_codepage,
5734 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735{
5736 TRANSACTION2_SPI_REQ *pSMB = NULL;
5737 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5738 int name_len;
5739 int rc = 0;
5740 int bytes_returned = 0;
5741 char *data_offset;
5742 __u16 params, param_offset, offset, byte_count, count;
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005743 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744
Joe Perchesf96637b2013-05-04 22:12:25 -05005745 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746
5747SetTimesRetry:
5748 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5749 (void **) &pSMBr);
5750 if (rc)
5751 return rc;
5752
5753 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5754 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005755 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5756 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 name_len++; /* trailing null */
5758 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005759 } else {
5760 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 }
5762
5763 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005764 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005766 /* BB find max SMB PDU from sess structure BB */
5767 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 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_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005774 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 offset = param_offset + params;
5776 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5777 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5778 pSMB->DataOffset = cpu_to_le16(offset);
5779 pSMB->SetupCount = 1;
5780 pSMB->Reserved3 = 0;
5781 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5782 byte_count = 3 /* pad */ + params + count;
5783
5784 pSMB->DataCount = cpu_to_le16(count);
5785 pSMB->ParameterCount = cpu_to_le16(params);
5786 pSMB->TotalDataCount = pSMB->DataCount;
5787 pSMB->TotalParameterCount = pSMB->ParameterCount;
5788 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5789 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5790 else
5791 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5792 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005793 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005794 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 pSMB->ByteCount = cpu_to_le16(byte_count);
5796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005798 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005799 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800
5801 cifs_buf_release(pSMB);
5802
5803 if (rc == -EAGAIN)
5804 goto SetTimesRetry;
5805
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005806 if (rc == -EOPNOTSUPP)
5807 return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
5808 nls_codepage, cifs_sb);
5809
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810 return rc;
5811}
5812
Jeff Layton654cf142009-07-09 20:02:49 -04005813static void
5814cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5815 const struct cifs_unix_set_info_args *args)
5816{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005817 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005818 u64 mode = args->mode;
5819
Eric W. Biederman49418b22013-02-06 00:57:56 -08005820 if (uid_valid(args->uid))
5821 uid = from_kuid(&init_user_ns, args->uid);
5822 if (gid_valid(args->gid))
5823 gid = from_kgid(&init_user_ns, args->gid);
5824
Jeff Layton654cf142009-07-09 20:02:49 -04005825 /*
5826 * Samba server ignores set of file size to zero due to bugs in some
5827 * older clients, but we should be precise - we use SetFileSize to
5828 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005829 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005830 * zero instead of -1 here
5831 */
5832 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5833 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5834 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5835 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5836 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005837 data_offset->Uid = cpu_to_le64(uid);
5838 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005839 /* better to leave device as zero when it is */
5840 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5841 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5842 data_offset->Permissions = cpu_to_le64(mode);
5843
5844 if (S_ISREG(mode))
5845 data_offset->Type = cpu_to_le32(UNIX_FILE);
5846 else if (S_ISDIR(mode))
5847 data_offset->Type = cpu_to_le32(UNIX_DIR);
5848 else if (S_ISLNK(mode))
5849 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5850 else if (S_ISCHR(mode))
5851 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5852 else if (S_ISBLK(mode))
5853 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5854 else if (S_ISFIFO(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5856 else if (S_ISSOCK(mode))
5857 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5858}
5859
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005861CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005862 const struct cifs_unix_set_info_args *args,
5863 u16 fid, u32 pid_of_opener)
5864{
5865 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005866 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005867 int rc = 0;
5868 u16 params, param_offset, offset, byte_count, count;
5869
Joe Perchesf96637b2013-05-04 22:12:25 -05005870 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005871 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5872
5873 if (rc)
5874 return rc;
5875
5876 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5877 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5878
5879 params = 6;
5880 pSMB->MaxSetupCount = 0;
5881 pSMB->Reserved = 0;
5882 pSMB->Flags = 0;
5883 pSMB->Timeout = 0;
5884 pSMB->Reserved2 = 0;
5885 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5886 offset = param_offset + params;
5887
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005888 data_offset = (char *)pSMB +
5889 offsetof(struct smb_hdr, Protocol) + offset;
5890
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005891 count = sizeof(FILE_UNIX_BASIC_INFO);
5892
5893 pSMB->MaxParameterCount = cpu_to_le16(2);
5894 /* BB find max SMB PDU from sess */
5895 pSMB->MaxDataCount = cpu_to_le16(1000);
5896 pSMB->SetupCount = 1;
5897 pSMB->Reserved3 = 0;
5898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5899 byte_count = 3 /* pad */ + params + count;
5900 pSMB->DataCount = cpu_to_le16(count);
5901 pSMB->ParameterCount = cpu_to_le16(params);
5902 pSMB->TotalDataCount = pSMB->DataCount;
5903 pSMB->TotalParameterCount = pSMB->ParameterCount;
5904 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5905 pSMB->DataOffset = cpu_to_le16(offset);
5906 pSMB->Fid = fid;
5907 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5908 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005909 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005910 pSMB->ByteCount = cpu_to_le16(byte_count);
5911
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005912 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005913
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005914 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005915 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005916 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005917 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5918 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005919
5920 /* Note: On -EAGAIN error only caller can retry on handle based calls
5921 since file handle passed in no longer valid */
5922
5923 return rc;
5924}
5925
5926int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005927CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005928 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005929 const struct cifs_unix_set_info_args *args,
5930 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931{
5932 TRANSACTION2_SPI_REQ *pSMB = NULL;
5933 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5934 int name_len;
5935 int rc = 0;
5936 int bytes_returned = 0;
5937 FILE_UNIX_BASIC_INFO *data_offset;
5938 __u16 params, param_offset, offset, count, byte_count;
5939
Joe Perchesf96637b2013-05-04 22:12:25 -05005940 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941setPermsRetry:
5942 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5943 (void **) &pSMBr);
5944 if (rc)
5945 return rc;
5946
5947 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5948 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005949 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005950 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 name_len++; /* trailing null */
5952 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005953 } else {
5954 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 }
5956
5957 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005958 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005960 /* BB find max SMB PDU from sess structure BB */
5961 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 pSMB->MaxSetupCount = 0;
5963 pSMB->Reserved = 0;
5964 pSMB->Flags = 0;
5965 pSMB->Timeout = 0;
5966 pSMB->Reserved2 = 0;
5967 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005968 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969 offset = param_offset + params;
Steve Frenchb019e112021-07-01 21:01:19 -05005970 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
5971 data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 memset(data_offset, 0, count);
5973 pSMB->DataOffset = cpu_to_le16(offset);
5974 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5975 pSMB->SetupCount = 1;
5976 pSMB->Reserved3 = 0;
5977 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5978 byte_count = 3 /* pad */ + params + count;
5979 pSMB->ParameterCount = cpu_to_le16(params);
5980 pSMB->DataCount = cpu_to_le16(count);
5981 pSMB->TotalParameterCount = pSMB->ParameterCount;
5982 pSMB->TotalDataCount = pSMB->DataCount;
5983 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5984 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005985 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005986
Jeff Layton654cf142009-07-09 20:02:49 -04005987 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988
5989 pSMB->ByteCount = cpu_to_le16(byte_count);
5990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005992 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005993 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994
Steve French0d817bc2008-05-22 02:02:03 +00005995 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996 if (rc == -EAGAIN)
5997 goto setPermsRetry;
5998 return rc;
5999}
6000
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006002/*
6003 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6004 * function used by listxattr and getxattr type calls. When ea_name is set,
6005 * it looks for that attribute name and stuffs that value into the EAData
6006 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6007 * buffer. In both cases, the return value is either the length of the
6008 * resulting data or a negative error code. If EAData is a NULL pointer then
6009 * the data isn't copied to it, but the length is returned.
6010 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006012CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006013 const unsigned char *searchName, const unsigned char *ea_name,
6014 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006015 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016{
6017 /* BB assumes one setup word */
6018 TRANSACTION2_QPI_REQ *pSMB = NULL;
6019 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006020 int remap = cifs_remap(cifs_sb);
6021 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022 int rc = 0;
6023 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006024 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006025 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006026 struct fea *temp_fea;
6027 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006028 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006029 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006030 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031
Joe Perchesf96637b2013-05-04 22:12:25 -05006032 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033QAllEAsRetry:
6034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6035 (void **) &pSMBr);
6036 if (rc)
6037 return rc;
6038
6039 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006040 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006041 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6042 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006043 list_len++; /* trailing null */
6044 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006045 } else {
6046 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 }
6048
Jeff Layton6e462b92010-02-10 16:18:26 -05006049 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 pSMB->TotalDataCount = 0;
6051 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006052 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006053 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 pSMB->MaxSetupCount = 0;
6055 pSMB->Reserved = 0;
6056 pSMB->Flags = 0;
6057 pSMB->Timeout = 0;
6058 pSMB->Reserved2 = 0;
6059 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006060 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061 pSMB->DataCount = 0;
6062 pSMB->DataOffset = 0;
6063 pSMB->SetupCount = 1;
6064 pSMB->Reserved3 = 0;
6065 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6066 byte_count = params + 1 /* pad */ ;
6067 pSMB->TotalParameterCount = cpu_to_le16(params);
6068 pSMB->ParameterCount = pSMB->TotalParameterCount;
6069 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6070 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006071 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 pSMB->ByteCount = cpu_to_le16(byte_count);
6073
6074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6076 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006077 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006078 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006080
6081
6082 /* BB also check enough total bytes returned */
6083 /* BB we need to improve the validity checking
6084 of these trans2 responses */
6085
6086 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006087 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006088 rc = -EIO; /* bad smb */
6089 goto QAllEAsOut;
6090 }
6091
6092 /* check that length of list is not more than bcc */
6093 /* check that each entry does not go beyond length
6094 of list */
6095 /* check that each element of each entry does not
6096 go beyond end of list */
6097 /* validate_trans2_offsets() */
6098 /* BB check if start of smb + data_offset > &bcc+ bcc */
6099
6100 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6101 ea_response_data = (struct fealist *)
6102 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6103
Jeff Layton6e462b92010-02-10 16:18:26 -05006104 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006105 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006106 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006107 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006108 /* didn't find the named attribute */
6109 if (ea_name)
6110 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006111 goto QAllEAsOut;
6112 }
6113
Jeff Layton0cd126b2010-02-10 16:18:26 -05006114 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006115 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006116 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006117 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006118 rc = -EIO;
6119 goto QAllEAsOut;
6120 }
6121
Jeff Laytonf0d38682010-02-10 16:18:26 -05006122 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006123 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 temp_fea = ea_response_data->list;
6125 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006126 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006127 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006128 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006129
Jeff Layton6e462b92010-02-10 16:18:26 -05006130 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006131 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006132 /* make sure we can read name_len and value_len */
6133 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006134 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006135 rc = -EIO;
6136 goto QAllEAsOut;
6137 }
6138
6139 name_len = temp_fea->name_len;
6140 value_len = le16_to_cpu(temp_fea->value_len);
6141 list_len -= name_len + 1 + value_len;
6142 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006143 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006144 rc = -EIO;
6145 goto QAllEAsOut;
6146 }
6147
Jeff Layton31c05192010-02-10 16:18:26 -05006148 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006149 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006150 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006151 temp_ptr += name_len + 1;
6152 rc = value_len;
6153 if (buf_size == 0)
6154 goto QAllEAsOut;
6155 if ((size_t)value_len > buf_size) {
6156 rc = -ERANGE;
6157 goto QAllEAsOut;
6158 }
6159 memcpy(EAData, temp_ptr, value_len);
6160 goto QAllEAsOut;
6161 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006162 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006163 /* account for prefix user. and trailing null */
6164 rc += (5 + 1 + name_len);
6165 if (rc < (int) buf_size) {
6166 memcpy(EAData, "user.", 5);
6167 EAData += 5;
6168 memcpy(EAData, temp_ptr, name_len);
6169 EAData += name_len;
6170 /* null terminate name */
6171 *EAData = 0;
6172 ++EAData;
6173 } else if (buf_size == 0) {
6174 /* skip copy - calc size only */
6175 } else {
6176 /* stop before overrun buffer */
6177 rc = -ERANGE;
6178 break;
6179 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006181 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006182 temp_fea = (struct fea *)temp_ptr;
6183 }
6184
Jeff Layton31c05192010-02-10 16:18:26 -05006185 /* didn't find the named attribute */
6186 if (ea_name)
6187 rc = -ENODATA;
6188
Jeff Laytonf0d38682010-02-10 16:18:26 -05006189QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006190 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191 if (rc == -EAGAIN)
6192 goto QAllEAsRetry;
6193
6194 return (ssize_t)rc;
6195}
6196
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006198CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6199 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006200 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006201 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202{
6203 struct smb_com_transaction2_spi_req *pSMB = NULL;
6204 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6205 struct fealist *parm_data;
6206 int name_len;
6207 int rc = 0;
6208 int bytes_returned = 0;
6209 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006210 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Joe Perchesf96637b2013-05-04 22:12:25 -05006212 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213SetEARetry:
6214 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6215 (void **) &pSMBr);
6216 if (rc)
6217 return rc;
6218
6219 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6220 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006221 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6222 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223 name_len++; /* trailing null */
6224 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006225 } else {
6226 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 }
6228
6229 params = 6 + name_len;
6230
6231 /* done calculating parms using name_len of file name,
6232 now use name_len to calculate length of ea name
6233 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006234 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235 name_len = 0;
6236 else
Steve French50c2f752007-07-13 00:33:32 +00006237 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006239 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006241 /* BB find max SMB PDU from sess */
6242 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 pSMB->MaxSetupCount = 0;
6244 pSMB->Reserved = 0;
6245 pSMB->Flags = 0;
6246 pSMB->Timeout = 0;
6247 pSMB->Reserved2 = 0;
6248 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006249 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250 offset = param_offset + params;
6251 pSMB->InformationLevel =
6252 cpu_to_le16(SMB_SET_FILE_EA);
6253
Arnd Bergmannade7db92018-02-02 16:48:47 +01006254 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6256 pSMB->DataOffset = cpu_to_le16(offset);
6257 pSMB->SetupCount = 1;
6258 pSMB->Reserved3 = 0;
6259 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6260 byte_count = 3 /* pad */ + params + count;
6261 pSMB->DataCount = cpu_to_le16(count);
6262 parm_data->list_len = cpu_to_le32(count);
6263 parm_data->list[0].EA_flags = 0;
6264 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006265 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006267 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006268 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 parm_data->list[0].name[name_len] = 0;
6270 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6271 /* caller ensures that ea_value_len is less than 64K but
6272 we need to ensure that it fits within the smb */
6273
Steve French50c2f752007-07-13 00:33:32 +00006274 /*BB add length check to see if it would fit in
6275 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006276 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6277 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006278 memcpy(parm_data->list[0].name+name_len+1,
6279 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
6281 pSMB->TotalDataCount = pSMB->DataCount;
6282 pSMB->ParameterCount = cpu_to_le16(params);
6283 pSMB->TotalParameterCount = pSMB->ParameterCount;
6284 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006285 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286 pSMB->ByteCount = cpu_to_le16(byte_count);
6287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6288 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006289 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006290 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291
6292 cifs_buf_release(pSMB);
6293
6294 if (rc == -EAGAIN)
6295 goto SetEARetry;
6296
6297 return rc;
6298}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006299#endif