blob: cc86a67225d1b87fc56f57dbd6e0ad700edb18ce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080038#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Pavel Shilovskyd9191312019-12-10 11:44:52 -080045#include "smb2proto.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040046#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070047#include "smbdirect.h"
Paulo Alcantara08744012018-11-14 17:24:29 -020048#ifdef CONFIG_CIFS_DFS_UPCALL
49#include "dfs_cache.h"
50#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#ifdef CONFIG_CIFS_POSIX
53static struct {
54 int index;
55 char *name;
56} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000057#ifdef CONFIG_CIFS_WEAK_PW_HASH
58 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000059 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000060#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000061 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000062 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 {BAD_PROT, "\2"}
64};
65#else
66static struct {
67 int index;
68 char *name;
69} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000070#ifdef CONFIG_CIFS_WEAK_PW_HASH
71 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000072 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000073#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000074 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 {BAD_PROT, "\2"}
76};
77#endif
78
Steve French39798772006-05-31 22:40:51 +000079/* define the number of elements in the cifs dialect array */
80#ifdef CONFIG_CIFS_POSIX
81#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000082#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000083#else
84#define CIFS_NUM_PROT 2
85#endif /* CIFS_WEAK_PW_HASH */
86#else /* not posix */
87#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000088#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000089#else
90#define CIFS_NUM_PROT 1
91#endif /* CONFIG_CIFS_WEAK_PW_HASH */
92#endif /* CIFS_POSIX */
93
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040094/*
95 * Mark as invalid, all open files on tree connections since they
96 * were closed when session to server was lost.
97 */
98void
99cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100{
101 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000102 struct list_head *tmp;
103 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400105 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500106 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400107 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000108 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000109 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400110 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 }
Steve French3afca262016-09-22 18:58:16 -0500112 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -0500113
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000114 mutex_lock(&tcon->crfid.fid_mutex);
115 tcon->crfid.is_valid = false;
Pavel Shilovskyd9191312019-12-10 11:44:52 -0800116 /* cached handle is not valid, so SMB2_CLOSE won't be sent below */
117 close_shroot_lease_locked(&tcon->crfid);
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000118 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
119 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -0500120
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400121 /*
122 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
123 * to this tcon.
124 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Paulo Alcantara08744012018-11-14 17:24:29 -0200127#ifdef CONFIG_CIFS_DFS_UPCALL
128static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
129 struct cifs_tcon *tcon)
130{
131 int rc;
132 struct dfs_cache_tgt_list tl;
133 struct dfs_cache_tgt_iterator *it = NULL;
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100134 char *tree;
Paulo Alcantara08744012018-11-14 17:24:29 -0200135 const char *tcp_host;
136 size_t tcp_host_len;
137 const char *dfs_host;
138 size_t dfs_host_len;
139
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100140 tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
141 if (!tree)
142 return -ENOMEM;
143
Paulo Alcantara08744012018-11-14 17:24:29 -0200144 if (tcon->ipc) {
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +1000145 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
146 tcon->ses->server->hostname);
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100147 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
148 goto out;
Paulo Alcantara08744012018-11-14 17:24:29 -0200149 }
150
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100151 if (!tcon->dfs_path) {
152 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
153 goto out;
154 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200155
156 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
157 if (rc)
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100158 goto out;
Paulo Alcantara08744012018-11-14 17:24:29 -0200159
160 extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
161 &tcp_host_len);
162
163 for (it = dfs_cache_get_tgt_iterator(&tl); it;
164 it = dfs_cache_get_next_tgt(&tl, it)) {
165 const char *tgt = dfs_cache_get_tgt_name(it);
166
167 extract_unc_hostname(tgt, &dfs_host, &dfs_host_len);
168
169 if (dfs_host_len != tcp_host_len
170 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
171 cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
172 __func__,
173 (int)dfs_host_len, dfs_host,
174 (int)tcp_host_len, tcp_host);
175 continue;
176 }
177
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +1000178 scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt);
Paulo Alcantara08744012018-11-14 17:24:29 -0200179
180 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
181 if (!rc)
182 break;
183 if (rc == -EREMOTE)
184 break;
185 }
186
187 if (!rc) {
188 if (it)
189 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
190 it);
191 else
192 rc = -ENOENT;
193 }
194 dfs_cache_free_tgts(&tl);
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100195out:
196 kfree(tree);
Paulo Alcantara08744012018-11-14 17:24:29 -0200197 return rc;
198}
199#else
200static inline int __cifs_reconnect_tcon(const struct nls_table *nlsc,
201 struct cifs_tcon *tcon)
202{
203 return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
204}
205#endif
206
Jeff Layton9162ab22009-09-03 12:07:17 -0400207/* reconnect the socket, tcon, and smb session if needed */
208static int
Steve French96daf2b2011-05-27 04:34:02 +0000209cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400210{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400211 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000212 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400213 struct TCP_Server_Info *server;
214 struct nls_table *nls_codepage;
Paulo Alcantara08744012018-11-14 17:24:29 -0200215 int retries;
Jeff Layton9162ab22009-09-03 12:07:17 -0400216
217 /*
218 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
219 * tcp and smb session status done differently for those three - in the
220 * calling routine
221 */
222 if (!tcon)
223 return 0;
224
225 ses = tcon->ses;
226 server = ses->server;
227
228 /*
229 * only tree disconnect, open, and write, (and ulogoff which does not
230 * have tcon) are allowed as we start force umount
231 */
232 if (tcon->tidStatus == CifsExiting) {
233 if (smb_command != SMB_COM_WRITE_ANDX &&
234 smb_command != SMB_COM_OPEN_ANDX &&
235 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500236 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
237 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400238 return -ENODEV;
239 }
240 }
241
Paulo Alcantara08744012018-11-14 17:24:29 -0200242 retries = server->nr_targets;
243
Jeff Layton9162ab22009-09-03 12:07:17 -0400244 /*
Paulo Alcantara08744012018-11-14 17:24:29 -0200245 * Give demultiplex thread up to 10 seconds to each target available for
246 * reconnect -- should be greater than cifs socket timeout which is 7
247 * seconds.
Jeff Layton9162ab22009-09-03 12:07:17 -0400248 */
249 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300250 rc = wait_event_interruptible_timeout(server->response_q,
251 (server->tcpStatus != CifsNeedReconnect),
252 10 * HZ);
253 if (rc < 0) {
254 cifs_dbg(FYI, "%s: aborting reconnect due to a received"
255 " signal by the process\n", __func__);
256 return -ERESTARTSYS;
257 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400258
Steve Frenchfd88ce92011-04-12 01:01:14 +0000259 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400260 if (server->tcpStatus != CifsNeedReconnect)
261 break;
262
Paulo Alcantara08744012018-11-14 17:24:29 -0200263 if (--retries)
264 continue;
265
Jeff Layton9162ab22009-09-03 12:07:17 -0400266 /*
267 * on "soft" mounts we wait once. Hard mounts keep
268 * retrying until process is killed or server comes
269 * back on-line
270 */
Jeff Laytond4025392011-02-07 08:54:35 -0500271 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500272 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400273 return -EHOSTDOWN;
274 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200275 retries = server->nr_targets;
Jeff Layton9162ab22009-09-03 12:07:17 -0400276 }
277
278 if (!ses->need_reconnect && !tcon->need_reconnect)
279 return 0;
280
281 nls_codepage = load_nls_default();
282
283 /*
284 * need to prevent multiple threads trying to simultaneously
285 * reconnect the same SMB session
286 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000287 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200288
289 /*
290 * Recheck after acquire mutex. If another thread is negotiating
291 * and the server never sends an answer the socket will be closed
292 * and tcpStatus set to reconnect.
293 */
294 if (server->tcpStatus == CifsNeedReconnect) {
295 rc = -EHOSTDOWN;
296 mutex_unlock(&ses->session_mutex);
297 goto out;
298 }
299
Jeff Layton198b5682010-04-24 07:57:48 -0400300 rc = cifs_negotiate_protocol(0, ses);
301 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400302 rc = cifs_setup_session(0, ses, nls_codepage);
303
304 /* do we need to reconnect tcon? */
305 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000306 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400307 goto out;
308 }
309
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400310 cifs_mark_open_files_invalid(tcon);
Paulo Alcantara08744012018-11-14 17:24:29 -0200311 rc = __cifs_reconnect_tcon(nls_codepage, tcon);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000312 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500313 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400314
Steve Frenchc318e6c2018-04-04 14:08:52 -0500315 if (rc) {
316 printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400317 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500318 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400319
Jeff Layton9162ab22009-09-03 12:07:17 -0400320 atomic_inc(&tconInfoReconnectCount);
321
322 /* tell server Unix caps we support */
323 if (ses->capabilities & CAP_UNIX)
324 reset_cifs_unix_caps(0, tcon, NULL, NULL);
325
326 /*
327 * Removed call to reopen open files here. It is safer (and faster) to
328 * reopen files one at a time as needed in read and write.
329 *
330 * FIXME: what about file locks? don't we need to reclaim them ASAP?
331 */
332
333out:
334 /*
335 * Check if handle based operation so we know whether we can continue
336 * or not without returning to caller to reset file handle
337 */
338 switch (smb_command) {
339 case SMB_COM_READ_ANDX:
340 case SMB_COM_WRITE_ANDX:
341 case SMB_COM_CLOSE:
342 case SMB_COM_FIND_CLOSE2:
343 case SMB_COM_LOCKING_ANDX:
344 rc = -EAGAIN;
345 }
346
347 unload_nls(nls_codepage);
348 return rc;
349}
350
Steve Frenchad7a2922008-02-07 23:25:02 +0000351/* Allocate and return pointer to an SMB request buffer, and set basic
352 SMB information in the SMB header. If the return code is zero, this
353 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354static int
Steve French96daf2b2011-05-27 04:34:02 +0000355small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000356 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
Jeff Laytonf5695992010-09-29 15:27:08 -0400358 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Jeff Layton9162ab22009-09-03 12:07:17 -0400360 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000361 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 return rc;
363
364 *request_buf = cifs_small_buf_get();
365 if (*request_buf == NULL) {
366 /* BB should we add a retry in here if not a writepage? */
367 return -ENOMEM;
368 }
369
Steve French63135e02007-07-17 17:34:02 +0000370 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000371 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Steve French790fe572007-07-07 19:25:05 +0000373 if (tcon != NULL)
374 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700375
Jeff Laytonf5695992010-09-29 15:27:08 -0400376 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000377}
378
Steve French12b3b8f2006-02-09 21:12:47 +0000379int
Steve French50c2f752007-07-13 00:33:32 +0000380small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000381 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000382{
383 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000384 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000385
Steve French5815449d2006-02-14 01:36:20 +0000386 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000387 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000388 return rc;
389
Steve French04fdabe2006-02-10 05:52:50 +0000390 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400391 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000392 if (ses->capabilities & CAP_UNICODE)
393 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000394 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000395 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
396
397 /* uid, tid can stay at zero as set in header assemble */
398
Steve French50c2f752007-07-13 00:33:32 +0000399 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000400 this function is used after 1st of session setup requests */
401
402 return rc;
403}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405/* If the return code is zero, this function must fill in request_buf pointer */
406static int
Steve French96daf2b2011-05-27 04:34:02 +0000407__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400408 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 *request_buf = cifs_buf_get();
411 if (*request_buf == NULL) {
412 /* BB should we add a retry in here if not a writepage? */
413 return -ENOMEM;
414 }
415 /* Although the original thought was we needed the response buf for */
416 /* potential retries of smb operations it turns out we can determine */
417 /* from the mid flags when the request buffer can be resent without */
418 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000419 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000420 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
422 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000423 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Steve French790fe572007-07-07 19:25:05 +0000425 if (tcon != NULL)
426 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700427
Jeff Laytonf5695992010-09-29 15:27:08 -0400428 return 0;
429}
430
431/* If the return code is zero, this function must fill in request_buf pointer */
432static int
Steve French96daf2b2011-05-27 04:34:02 +0000433smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400434 void **request_buf, void **response_buf)
435{
436 int rc;
437
438 rc = cifs_reconnect_tcon(tcon, smb_command);
439 if (rc)
440 return rc;
441
442 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
443}
444
445static int
Steve French96daf2b2011-05-27 04:34:02 +0000446smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400447 void **request_buf, void **response_buf)
448{
449 if (tcon->ses->need_reconnect || tcon->need_reconnect)
450 return -EHOSTDOWN;
451
452 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453}
454
Steve French50c2f752007-07-13 00:33:32 +0000455static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
Jeff Layton12df83c2011-01-20 13:36:51 -0500457 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Jeff Layton12df83c2011-01-20 13:36:51 -0500459 /* check for plausible wct */
460 if (pSMB->hdr.WordCount < 10)
461 goto vt2_err;
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500464 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
465 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
466 goto vt2_err;
467
Jeff Layton12df83c2011-01-20 13:36:51 -0500468 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
469 if (total_size >= 512)
470 goto vt2_err;
471
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400472 /* check that bcc is at least as big as parms + data, and that it is
473 * less than negotiated smb buffer
474 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500475 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
476 if (total_size > get_bcc(&pSMB->hdr) ||
477 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
478 goto vt2_err;
479
480 return 0;
481vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000482 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500484 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
Jeff Layton690c5222011-01-20 13:36:51 -0500486
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400487static int
Jeff Layton3f618222013-06-12 19:52:14 -0500488decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400489{
490 int rc = 0;
491 u16 count;
492 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500493 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400494
495 count = get_bcc(&pSMBr->hdr);
496 if (count < SMB1_CLIENT_GUID_SIZE)
497 return -EIO;
498
499 spin_lock(&cifs_tcp_ses_lock);
500 if (server->srv_count > 1) {
501 spin_unlock(&cifs_tcp_ses_lock);
502 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
503 cifs_dbg(FYI, "server UID changed\n");
504 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
505 }
506 } else {
507 spin_unlock(&cifs_tcp_ses_lock);
508 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
509 }
510
511 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500512 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400513 } else {
514 count -= SMB1_CLIENT_GUID_SIZE;
515 rc = decode_negTokenInit(
516 pSMBr->u.extended_response.SecurityBlob, count, server);
517 if (rc != 1)
518 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400519 }
520
521 return 0;
522}
523
Jeff Layton9ddec562013-05-26 07:00:58 -0400524int
Jeff Layton38d77c52013-05-26 07:01:00 -0400525cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400526{
Jeff Layton502858822013-06-27 12:45:00 -0400527 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
528 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400529 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
530
531 /*
532 * Is signing required by mnt options? If not then check
533 * global_secflags to see if it is there.
534 */
535 if (!mnt_sign_required)
536 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
537 CIFSSEC_MUST_SIGN);
538
539 /*
540 * If signing is required then it's automatically enabled too,
541 * otherwise, check to see if the secflags allow it.
542 */
543 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
544 (global_secflags & CIFSSEC_MAY_SIGN);
545
546 /* If server requires signing, does client allow it? */
547 if (srv_sign_required) {
548 if (!mnt_sign_enabled) {
549 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
550 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400551 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400552 server->sign = true;
553 }
554
555 /* If client requires signing, does server allow it? */
556 if (mnt_sign_required) {
557 if (!srv_sign_enabled) {
558 cifs_dbg(VFS, "Server does not support signing!");
559 return -ENOTSUPP;
560 }
561 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400562 }
563
Long Libb4c0412018-04-17 12:17:08 -0700564 if (cifs_rdma_enabled(server) && server->sign)
565 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled");
566
Jeff Layton9ddec562013-05-26 07:00:58 -0400567 return 0;
568}
569
Jeff Layton2190eca2013-05-26 07:00:57 -0400570#ifdef CONFIG_CIFS_WEAK_PW_HASH
571static int
Jeff Layton3f618222013-06-12 19:52:14 -0500572decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400573{
574 __s16 tmp;
575 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
576
577 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
578 return -EOPNOTSUPP;
579
Jeff Layton2190eca2013-05-26 07:00:57 -0400580 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
581 server->maxReq = min_t(unsigned int,
582 le16_to_cpu(rsp->MaxMpxCount),
583 cifs_max_pending);
584 set_credits(server, server->maxReq);
585 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400586 /* even though we do not use raw we might as well set this
587 accurately, in case we ever find a need for it */
588 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
589 server->max_rw = 0xFF00;
590 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
591 } else {
592 server->max_rw = 0;/* do not need to use raw anyway */
593 server->capabilities = CAP_MPX_MODE;
594 }
595 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
596 if (tmp == -1) {
597 /* OS/2 often does not set timezone therefore
598 * we must use server time to calc time zone.
599 * Could deviate slightly from the right zone.
600 * Smallest defined timezone difference is 15 minutes
601 * (i.e. Nepal). Rounding up/down is done to match
602 * this requirement.
603 */
604 int val, seconds, remain, result;
Arnd Bergmann95390202018-06-19 17:27:58 +0200605 struct timespec64 ts;
606 time64_t utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400607 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
608 rsp->SrvTime.Time, 0);
Arnd Bergmann95390202018-06-19 17:27:58 +0200609 cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
610 ts.tv_sec, utc,
611 utc - ts.tv_sec);
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700612 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400613 seconds = abs(val);
614 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
615 remain = seconds % MIN_TZ_ADJ;
616 if (remain >= (MIN_TZ_ADJ / 2))
617 result += MIN_TZ_ADJ;
618 if (val < 0)
619 result = -result;
620 server->timeAdj = result;
621 } else {
622 server->timeAdj = (int)tmp;
623 server->timeAdj *= 60; /* also in seconds */
624 }
625 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
626
627
628 /* BB get server time for time conversions and add
629 code to use it and timezone since this is not UTC */
630
631 if (rsp->EncryptionKeyLength ==
632 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
633 memcpy(server->cryptkey, rsp->EncryptionKey,
634 CIFS_CRYPTO_KEY_SIZE);
635 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
636 return -EIO; /* need cryptkey unless plain text */
637 }
638
639 cifs_dbg(FYI, "LANMAN negotiated\n");
640 return 0;
641}
642#else
643static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500644decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400645{
646 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
647 return -EOPNOTSUPP;
648}
649#endif
650
Jeff Layton91934002013-05-26 07:00:58 -0400651static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500652should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400653{
Jeff Layton3f618222013-06-12 19:52:14 -0500654 switch (sectype) {
655 case RawNTLMSSP:
656 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400657 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500658 case Unspecified:
659 if (global_secflags &
660 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
661 return true;
662 /* Fallthrough */
663 default:
664 return false;
665 }
Jeff Layton91934002013-05-26 07:00:58 -0400666}
667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400669CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 NEGOTIATE_REQ *pSMB;
672 NEGOTIATE_RSP *pSMBr;
673 int rc = 0;
674 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000675 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400676 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 u16 count;
678
Jeff Layton3534b852013-05-24 07:41:01 -0400679 if (!server) {
680 WARN(1, "%s: server is NULL!\n", __func__);
681 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
Jeff Layton3534b852013-05-24 07:41:01 -0400683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
685 (void **) &pSMB, (void **) &pSMBr);
686 if (rc)
687 return rc;
Steve French750d1152006-06-27 06:28:30 +0000688
Pavel Shilovsky88257362012-05-23 14:01:59 +0400689 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000690 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000691
Jeff Layton3f618222013-06-12 19:52:14 -0500692 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400693 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000694 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
695 }
Steve French50c2f752007-07-13 00:33:32 +0000696
Steve French39798772006-05-31 22:40:51 +0000697 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000698 /*
699 * We know that all the name entries in the protocols array
700 * are short (< 16 bytes anyway) and are NUL terminated.
701 */
Steve French50c2f752007-07-13 00:33:32 +0000702 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000703 size_t len = strlen(protocols[i].name) + 1;
704
705 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
706 count += len;
Steve French39798772006-05-31 22:40:51 +0000707 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000708 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 pSMB->ByteCount = cpu_to_le16(count);
710
711 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
712 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000713 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000714 goto neg_err_exit;
715
Jeff Layton9bf67e52010-04-24 07:57:46 -0400716 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500717 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000718 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400719 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000720 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000721 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000722 could not negotiate a common dialect */
723 rc = -EOPNOTSUPP;
724 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000725 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400726 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500727 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400728 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000729 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000730 /* unknown wct */
731 rc = -EOPNOTSUPP;
732 goto neg_err_exit;
733 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400734 /* else wct == 17, NTLM or better */
735
Steve French96daf2b2011-05-27 04:34:02 +0000736 server->sec_mode = pSMBr->SecurityMode;
737 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500738 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000739
Steve French254e55e2006-06-04 05:53:15 +0000740 /* one byte, so no need to convert this or EncryptionKeyLen from
741 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300742 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
743 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400744 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000745 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400746 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000747 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500748 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000749 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000750 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
751 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400752
Jeff Laytone598d1d82013-05-26 07:00:59 -0400753 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
754 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500755 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000756 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100757 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
758 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400759 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500760 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400761 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000762 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400763 } else {
764 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000765 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400766 }
Steve French254e55e2006-06-04 05:53:15 +0000767
768signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400769 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400770 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000771neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700772 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000773
Joe Perchesf96637b2013-05-04 22:12:25 -0500774 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return rc;
776}
777
778int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400779CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Joe Perchesf96637b2013-05-04 22:12:25 -0500784 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500785
786 /* BB: do we need to check this? These should never be NULL. */
787 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
788 return -EIO;
789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500791 * No need to return error on this operation if tid invalidated and
792 * closed on server already e.g. due to tcp session crashing. Also,
793 * the tcon is no longer on the list, so no need to take lock before
794 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 */
Steve French268875b2009-06-25 00:29:21 +0000796 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000797 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Steve French50c2f752007-07-13 00:33:32 +0000799 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700800 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500801 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 return rc;
Steve French133672e2007-11-13 22:41:37 +0000803
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400804 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700805 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500807 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Steve French50c2f752007-07-13 00:33:32 +0000809 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500810 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (rc == -EAGAIN)
812 rc = 0;
813
814 return rc;
815}
816
Jeff Layton766fdbb2011-01-11 07:24:21 -0500817/*
818 * This is a no-op for now. We're not really interested in the reply, but
819 * rather in the fact that the server sent one and that server->lstrp
820 * gets updated.
821 *
822 * FIXME: maybe we should consider checking that the reply matches request?
823 */
824static void
825cifs_echo_callback(struct mid_q_entry *mid)
826{
827 struct TCP_Server_Info *server = mid->callback_data;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800828 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500829
830 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800831 add_credits(server, &credits, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500832}
833
834int
835CIFSSMBEcho(struct TCP_Server_Info *server)
836{
837 ECHO_REQ *smb;
838 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800839 struct kvec iov[2];
840 struct smb_rqst rqst = { .rq_iov = iov,
841 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500842
Joe Perchesf96637b2013-05-04 22:12:25 -0500843 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500844
845 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
846 if (rc)
847 return rc;
848
Steve French26c9cb62017-05-02 13:35:20 -0500849 if (server->capabilities & CAP_UNICODE)
850 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
851
Jeff Layton766fdbb2011-01-11 07:24:21 -0500852 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000853 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500854 smb->hdr.WordCount = 1;
855 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400856 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500857 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000858 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800859
860 iov[0].iov_len = 4;
861 iov[0].iov_base = smb;
862 iov[1].iov_len = get_rfc1002_length(smb);
863 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500864
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800865 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +1000866 server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500867 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500868 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500869
870 cifs_small_buf_release(smb);
871
872 return rc;
873}
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400876CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 LOGOFF_ANDX_REQ *pSMB;
879 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Joe Perchesf96637b2013-05-04 22:12:25 -0500881 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500882
883 /*
884 * BB: do we need to check validity of ses and server? They should
885 * always be valid since we have an active reference. If not, that
886 * should probably be a BUG()
887 */
888 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return -EIO;
890
Steve Frenchd7b619c2010-02-25 05:36:46 +0000891 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000892 if (ses->need_reconnect)
893 goto session_already_dead; /* no need to send SMBlogoff if uid
894 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
896 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000897 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 return rc;
899 }
900
Pavel Shilovsky88257362012-05-23 14:01:59 +0400901 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700902
Jeff Layton38d77c52013-05-26 07:01:00 -0400903 if (ses->server->sign)
904 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 pSMB->hdr.Uid = ses->Suid;
907
908 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400909 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700910 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000911session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000912 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000915 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 error */
917 if (rc == -EAGAIN)
918 rc = 0;
919 return rc;
920}
921
922int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400923CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
924 const char *fileName, __u16 type,
925 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000926{
927 TRANSACTION2_SPI_REQ *pSMB = NULL;
928 TRANSACTION2_SPI_RSP *pSMBr = NULL;
929 struct unlink_psx_rq *pRqD;
930 int name_len;
931 int rc = 0;
932 int bytes_returned = 0;
933 __u16 params, param_offset, offset, byte_count;
934
Joe Perchesf96637b2013-05-04 22:12:25 -0500935 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000936PsxDelete:
937 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
938 (void **) &pSMBr);
939 if (rc)
940 return rc;
941
942 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
943 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600944 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
945 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000946 name_len++; /* trailing null */
947 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000948 } else {
949 name_len = copy_path_name(pSMB->FileName, fileName);
Steve French2d785a52007-07-15 01:48:57 +0000950 }
951
952 params = 6 + name_len;
953 pSMB->MaxParameterCount = cpu_to_le16(2);
954 pSMB->MaxDataCount = 0; /* BB double check this with jra */
955 pSMB->MaxSetupCount = 0;
956 pSMB->Reserved = 0;
957 pSMB->Flags = 0;
958 pSMB->Timeout = 0;
959 pSMB->Reserved2 = 0;
960 param_offset = offsetof(struct smb_com_transaction2_spi_req,
961 InformationLevel) - 4;
962 offset = param_offset + params;
963
964 /* Setup pointer to Request Data (inode type) */
965 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
966 pRqD->type = cpu_to_le16(type);
967 pSMB->ParameterOffset = cpu_to_le16(param_offset);
968 pSMB->DataOffset = cpu_to_le16(offset);
969 pSMB->SetupCount = 1;
970 pSMB->Reserved3 = 0;
971 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
972 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
973
974 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
975 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
976 pSMB->ParameterCount = cpu_to_le16(params);
977 pSMB->TotalParameterCount = pSMB->ParameterCount;
978 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
979 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000980 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000981 pSMB->ByteCount = cpu_to_le16(byte_count);
982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000984 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500985 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000986 cifs_buf_release(pSMB);
987
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400988 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000989
990 if (rc == -EAGAIN)
991 goto PsxDelete;
992
993 return rc;
994}
995
996int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700997CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
998 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
1000 DELETE_FILE_REQ *pSMB = NULL;
1001 DELETE_FILE_RSP *pSMBr = NULL;
1002 int rc = 0;
1003 int bytes_returned;
1004 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001005 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007DelFileRetry:
1008 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
1009 (void **) &pSMBr);
1010 if (rc)
1011 return rc;
1012
1013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -07001014 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
1015 PATH_MAX, cifs_sb->local_nls,
1016 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 name_len++; /* trailing null */
1018 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001019 } else {
1020 name_len = copy_path_name(pSMB->fileName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 }
1022 pSMB->SearchAttributes =
1023 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
1024 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001025 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001029 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +00001030 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001031 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 cifs_buf_release(pSMB);
1034 if (rc == -EAGAIN)
1035 goto DelFileRetry;
1036
1037 return rc;
1038}
1039
1040int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001041CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1042 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
1044 DELETE_DIRECTORY_REQ *pSMB = NULL;
1045 DELETE_DIRECTORY_RSP *pSMBr = NULL;
1046 int rc = 0;
1047 int bytes_returned;
1048 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001049 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Joe Perchesf96637b2013-05-04 22:12:25 -05001051 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052RmDirRetry:
1053 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
1054 (void **) &pSMBr);
1055 if (rc)
1056 return rc;
1057
1058 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001059 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1060 PATH_MAX, cifs_sb->local_nls,
1061 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 name_len++; /* trailing null */
1063 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001064 } else {
1065 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 }
1067
1068 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001069 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001073 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001074 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001075 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 cifs_buf_release(pSMB);
1078 if (rc == -EAGAIN)
1079 goto RmDirRetry;
1080 return rc;
1081}
1082
1083int
Steve Frenchc3ca78e2019-09-25 00:32:13 -05001084CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
1085 struct cifs_tcon *tcon, const char *name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001086 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
1088 int rc = 0;
1089 CREATE_DIRECTORY_REQ *pSMB = NULL;
1090 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1091 int bytes_returned;
1092 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001093 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
Joe Perchesf96637b2013-05-04 22:12:25 -05001095 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096MkDirRetry:
1097 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1098 (void **) &pSMBr);
1099 if (rc)
1100 return rc;
1101
1102 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001103 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001104 PATH_MAX, cifs_sb->local_nls,
1105 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 name_len++; /* trailing null */
1107 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001108 } else {
1109 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 }
1111
1112 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001113 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1115 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1116 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001117 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001118 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001119 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 cifs_buf_release(pSMB);
1122 if (rc == -EAGAIN)
1123 goto MkDirRetry;
1124 return rc;
1125}
1126
Steve French2dd29d32007-04-23 22:07:35 +00001127int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001128CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1129 __u32 posix_flags, __u64 mode, __u16 *netfid,
1130 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1131 const char *name, const struct nls_table *nls_codepage,
1132 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001133{
1134 TRANSACTION2_SPI_REQ *pSMB = NULL;
1135 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1136 int name_len;
1137 int rc = 0;
1138 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001139 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001140 OPEN_PSX_REQ *pdata;
1141 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001142
Joe Perchesf96637b2013-05-04 22:12:25 -05001143 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001144PsxCreat:
1145 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1146 (void **) &pSMBr);
1147 if (rc)
1148 return rc;
1149
1150 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1151 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001152 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1153 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001154 name_len++; /* trailing null */
1155 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001156 } else {
1157 name_len = copy_path_name(pSMB->FileName, name);
Steve French2dd29d32007-04-23 22:07:35 +00001158 }
1159
1160 params = 6 + name_len;
1161 count = sizeof(OPEN_PSX_REQ);
1162 pSMB->MaxParameterCount = cpu_to_le16(2);
1163 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1164 pSMB->MaxSetupCount = 0;
1165 pSMB->Reserved = 0;
1166 pSMB->Flags = 0;
1167 pSMB->Timeout = 0;
1168 pSMB->Reserved2 = 0;
1169 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001170 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001171 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001172 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001173 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001174 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001175 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001176 pdata->OpenFlags = cpu_to_le32(*pOplock);
1177 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1178 pSMB->DataOffset = cpu_to_le16(offset);
1179 pSMB->SetupCount = 1;
1180 pSMB->Reserved3 = 0;
1181 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1182 byte_count = 3 /* pad */ + params + count;
1183
1184 pSMB->DataCount = cpu_to_le16(count);
1185 pSMB->ParameterCount = cpu_to_le16(params);
1186 pSMB->TotalDataCount = pSMB->DataCount;
1187 pSMB->TotalParameterCount = pSMB->ParameterCount;
1188 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1189 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001190 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001191 pSMB->ByteCount = cpu_to_le16(byte_count);
1192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1194 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001195 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001196 goto psx_create_err;
1197 }
1198
Joe Perchesf96637b2013-05-04 22:12:25 -05001199 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001200 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1201
Jeff Layton820a8032011-05-04 08:05:26 -04001202 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001203 rc = -EIO; /* bad smb */
1204 goto psx_create_err;
1205 }
1206
1207 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001208 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001209 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001210
Steve French2dd29d32007-04-23 22:07:35 +00001211 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001212 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001213 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1214 /* Let caller know file was created so we can set the mode. */
1215 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001216 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001217 *pOplock |= CIFS_CREATE_ACTION;
1218 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001219 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1220 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001221 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001222 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001223 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001224 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001225 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001226 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001227 goto psx_create_err;
1228 }
Steve French50c2f752007-07-13 00:33:32 +00001229 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001230 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001231 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001232 }
Steve French2dd29d32007-04-23 22:07:35 +00001233
1234psx_create_err:
1235 cifs_buf_release(pSMB);
1236
Steve French65bc98b2009-07-10 15:27:25 +00001237 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001238 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001239 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001240 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001241
1242 if (rc == -EAGAIN)
1243 goto PsxCreat;
1244
Steve French50c2f752007-07-13 00:33:32 +00001245 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001246}
1247
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248static __u16 convert_disposition(int disposition)
1249{
1250 __u16 ofun = 0;
1251
1252 switch (disposition) {
1253 case FILE_SUPERSEDE:
1254 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1255 break;
1256 case FILE_OPEN:
1257 ofun = SMBOPEN_OAPPEND;
1258 break;
1259 case FILE_CREATE:
1260 ofun = SMBOPEN_OCREATE;
1261 break;
1262 case FILE_OPEN_IF:
1263 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1264 break;
1265 case FILE_OVERWRITE:
1266 ofun = SMBOPEN_OTRUNC;
1267 break;
1268 case FILE_OVERWRITE_IF:
1269 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1270 break;
1271 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001272 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 ofun = SMBOPEN_OAPPEND; /* regular open */
1274 }
1275 return ofun;
1276}
1277
Jeff Layton35fc37d2008-05-14 10:22:03 -07001278static int
1279access_flags_to_smbopen_mode(const int access_flags)
1280{
1281 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1282
1283 if (masked_flags == GENERIC_READ)
1284 return SMBOPEN_READ;
1285 else if (masked_flags == GENERIC_WRITE)
1286 return SMBOPEN_WRITE;
1287
1288 /* just go for read/write */
1289 return SMBOPEN_READWRITE;
1290}
1291
Steve Frencha9d02ad2005-08-24 23:06:05 -07001292int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001293SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001294 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001295 const int access_flags, const int create_options, __u16 *netfid,
1296 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297 const struct nls_table *nls_codepage, int remap)
1298{
1299 int rc = -EACCES;
1300 OPENX_REQ *pSMB = NULL;
1301 OPENX_RSP *pSMBr = NULL;
1302 int bytes_returned;
1303 int name_len;
1304 __u16 count;
1305
1306OldOpenRetry:
1307 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1308 (void **) &pSMBr);
1309 if (rc)
1310 return rc;
1311
1312 pSMB->AndXCommand = 0xFF; /* none */
1313
1314 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1315 count = 1; /* account for one byte pad to word boundary */
1316 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001317 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1318 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001319 name_len++; /* trailing null */
1320 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001321 } else {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001322 count = 0; /* no pad */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001323 name_len = copy_path_name(pSMB->fileName, fileName);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001324 }
1325 if (*pOplock & REQ_OPLOCK)
1326 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001327 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001328 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001329
Steve Frencha9d02ad2005-08-24 23:06:05 -07001330 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001331 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001332 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1333 /* set file as system file if special file such
1334 as fifo and server expecting SFU style and
1335 no Unix extensions */
1336
Steve French790fe572007-07-07 19:25:05 +00001337 if (create_options & CREATE_OPTION_SPECIAL)
1338 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001339 else /* BB FIXME BB */
1340 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001341
Jeff Layton67750fb2008-05-09 22:28:02 +00001342 if (create_options & CREATE_OPTION_READONLY)
1343 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001344
1345 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001346/* pSMB->CreateOptions = cpu_to_le32(create_options &
1347 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001348 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001349
1350 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001351 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001352 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001353 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001354
1355 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001357 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001358 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001359 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001360 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001361 } else {
1362 /* BB verify if wct == 15 */
1363
Steve French582d21e2008-05-13 04:54:12 +00001364/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001365
1366 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1367 /* Let caller know file was created so we can set the mode. */
1368 /* Do we care about the CreateAction in any other cases? */
1369 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001370/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001371 *pOplock |= CIFS_CREATE_ACTION; */
1372 /* BB FIXME END */
1373
Steve French790fe572007-07-07 19:25:05 +00001374 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001375 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1376 pfile_info->LastAccessTime = 0; /* BB fixme */
1377 pfile_info->LastWriteTime = 0; /* BB fixme */
1378 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001379 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001380 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001381 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001382 pfile_info->AllocationSize =
1383 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1384 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001385 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001386 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001387 }
1388 }
1389
1390 cifs_buf_release(pSMB);
1391 if (rc == -EAGAIN)
1392 goto OldOpenRetry;
1393 return rc;
1394}
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001397CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1398 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399{
Colin Ian King1afdea42019-07-23 16:09:19 +01001400 int rc;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001401 OPEN_REQ *req = NULL;
1402 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 int bytes_returned;
1404 int name_len;
1405 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001406 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1407 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001408 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001409 const struct nls_table *nls = cifs_sb->local_nls;
1410 int create_options = oparms->create_options;
1411 int desired_access = oparms->desired_access;
1412 int disposition = oparms->disposition;
1413 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
1415openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001416 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1417 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 if (rc)
1419 return rc;
1420
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001421 /* no commands go after this */
1422 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001424 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1425 /* account for one byte pad to word boundary */
1426 count = 1;
1427 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1428 path, PATH_MAX, nls, remap);
1429 /* trailing null */
1430 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001432 req->NameLength = cpu_to_le16(name_len);
1433 } else {
1434 /* BB improve check for buffer overruns BB */
1435 /* no pad */
1436 count = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001437 name_len = copy_path_name(req->fileName, path);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001438 req->NameLength = cpu_to_le16(name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001440
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001441 if (*oplock & REQ_OPLOCK)
1442 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1443 else if (*oplock & REQ_BATCHOPLOCK)
1444 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1445
1446 req->DesiredAccess = cpu_to_le32(desired_access);
1447 req->AllocationSize = 0;
1448
1449 /*
1450 * Set file as system file if special file such as fifo and server
1451 * expecting SFU style and no Unix extensions.
1452 */
1453 if (create_options & CREATE_OPTION_SPECIAL)
1454 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1455 else
1456 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1457
1458 /*
1459 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1460 * sensitive checks for other servers such as Samba.
1461 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001463 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Jeff Layton67750fb2008-05-09 22:28:02 +00001465 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001466 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001467
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001468 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1469 req->CreateDisposition = cpu_to_le32(disposition);
1470 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1471
Steve French09d1db52005-04-28 22:41:08 -07001472 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001473 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1474 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001477 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001479 req->ByteCount = cpu_to_le16(count);
1480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1481 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001482 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001484 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001485 cifs_buf_release(req);
1486 if (rc == -EAGAIN)
1487 goto openRetry;
1488 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001490
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001491 /* 1 byte no need to le_to_cpu */
1492 *oplock = rsp->OplockLevel;
1493 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001494 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001495
1496 /* Let caller know file was created so we can set the mode. */
1497 /* Do we care about the CreateAction in any other cases? */
1498 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1499 *oplock |= CIFS_CREATE_ACTION;
1500
1501 if (buf) {
1502 /* copy from CreationTime to Attributes */
1503 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1504 /* the file_info buf is endian converted by caller */
1505 buf->AllocationSize = rsp->AllocationSize;
1506 buf->EndOfFile = rsp->EndOfFile;
1507 buf->NumberOfLinks = cpu_to_le32(1);
1508 buf->DeletePending = 0;
1509 }
1510
1511 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 return rc;
1513}
1514
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001515/*
1516 * Discard any remaining data in the current SMB. To do this, we borrow the
1517 * current bigbuf.
1518 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001519int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001520cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001521{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001522 unsigned int rfclen = server->pdu_size;
1523 int remaining = rfclen + server->vals->header_preamble_size -
1524 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001525
1526 while (remaining > 0) {
1527 int length;
1528
1529 length = cifs_read_from_socket(server, server->bigbuf,
1530 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001531 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001532 if (length < 0)
1533 return length;
1534 server->total_read += length;
1535 remaining -= length;
1536 }
1537
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001538 return 0;
1539}
1540
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001541static int
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001542__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1543 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001544{
1545 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001546
Pavel Shilovsky350be252017-04-10 10:31:33 -07001547 length = cifs_discard_remaining_data(server);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001548 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001549 mid->resp_buf = server->smallbuf;
1550 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001551 return length;
1552}
1553
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001554static int
1555cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1556{
1557 struct cifs_readdata *rdata = mid->callback_data;
1558
1559 return __cifs_readv_discard(server, mid, rdata->result);
1560}
1561
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001562int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001563cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1564{
1565 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001566 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001567 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001568 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001569 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001570 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001571 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572
Joe Perchesf96637b2013-05-04 22:12:25 -05001573 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1574 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001575
1576 /*
1577 * read the rest of READ_RSP header (sans Data array), or whatever we
1578 * can if there's not enough data. At this point, we've read down to
1579 * the Mid.
1580 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001581 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001582 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001583
Al Viroa6137302016-01-09 19:37:16 -05001584 length = cifs_read_from_socket(server,
1585 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001586 if (length < 0)
1587 return length;
1588 server->total_read += length;
1589
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001590 if (server->ops->is_session_expired &&
1591 server->ops->is_session_expired(buf)) {
1592 cifs_reconnect(server);
1593 wake_up(&server->response_q);
1594 return -1;
1595 }
1596
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001597 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -08001598 server->ops->is_status_pending(buf, server)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001599 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001600 return -1;
1601 }
1602
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001603 /* set up first two iov for signature check and to get credits */
1604 rdata->iov[0].iov_base = buf;
Pavel Shilovskybb1bccb2019-01-17 16:18:38 -08001605 rdata->iov[0].iov_len = server->vals->header_preamble_size;
1606 rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1607 rdata->iov[1].iov_len =
1608 server->total_read - server->vals->header_preamble_size;
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001609 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1610 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1611 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1612 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1613
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001614 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001615 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001616 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001617 cifs_dbg(FYI, "%s: server returned error %d\n",
1618 __func__, rdata->result);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001619 /* normal error on read response */
1620 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001621 }
1622
1623 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001624 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001625 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1626 __func__, server->total_read,
1627 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001628 rdata->result = -EIO;
1629 return cifs_readv_discard(server, mid);
1630 }
1631
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001632 data_offset = server->ops->read_data_offset(buf) +
1633 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001634 if (data_offset < server->total_read) {
1635 /*
1636 * win2k8 sometimes sends an offset of 0 when the read
1637 * is beyond the EOF. Treat it as if the data starts just after
1638 * the header.
1639 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001640 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1641 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001642 data_offset = server->total_read;
1643 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1644 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001645 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1646 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001647 rdata->result = -EIO;
1648 return cifs_readv_discard(server, mid);
1649 }
1650
Joe Perchesf96637b2013-05-04 22:12:25 -05001651 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1652 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001653
1654 len = data_offset - server->total_read;
1655 if (len > 0) {
1656 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001657 length = cifs_read_from_socket(server,
1658 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001659 if (length < 0)
1660 return length;
1661 server->total_read += length;
1662 }
1663
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001664 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001665#ifdef CONFIG_CIFS_SMB_DIRECT
1666 use_rdma_mr = rdata->mr;
1667#endif
1668 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1669 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001670 /* data_len is corrupt -- discard frame */
1671 rdata->result = -EIO;
1672 return cifs_readv_discard(server, mid);
1673 }
1674
Jeff Layton8321fec2012-09-19 06:22:32 -07001675 length = rdata->read_into_pages(server, rdata, data_len);
1676 if (length < 0)
1677 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001678
Jeff Layton8321fec2012-09-19 06:22:32 -07001679 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001680
Joe Perchesf96637b2013-05-04 22:12:25 -05001681 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1682 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001683
1684 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001685 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001686 return cifs_readv_discard(server, mid);
1687
1688 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001689 mid->resp_buf = server->smallbuf;
1690 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001691 return length;
1692}
1693
1694static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001695cifs_readv_callback(struct mid_q_entry *mid)
1696{
1697 struct cifs_readdata *rdata = mid->callback_data;
1698 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1699 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001700 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1701 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001702 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001703 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001704 .rq_npages = rdata->nr_pages,
1705 .rq_pagesz = rdata->pagesz,
1706 .rq_tailsz = rdata->tailsz };
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001707 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001708
Joe Perchesf96637b2013-05-04 22:12:25 -05001709 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1710 __func__, mid->mid, mid->mid_state, rdata->result,
1711 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001712
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001713 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001714 case MID_RESPONSE_RECEIVED:
1715 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001716 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001717 int rc = 0;
1718
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001719 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001720 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001721 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001722 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1723 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001724 }
1725 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001726 task_io_account_read(rdata->got_bytes);
1727 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001728 break;
1729 case MID_REQUEST_SUBMITTED:
1730 case MID_RETRY_NEEDED:
1731 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001732 if (server->sign && rdata->got_bytes)
1733 /* reset bytes number since we can not check a sign */
1734 rdata->got_bytes = 0;
1735 /* FIXME: should this be counted toward the initiating task? */
1736 task_io_account_read(rdata->got_bytes);
1737 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001738 break;
1739 default:
1740 rdata->result = -EIO;
1741 }
1742
Jeff Laytonda472fc2012-03-23 14:40:53 -04001743 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001744 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001745 add_credits(server, &credits, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001746}
1747
1748/* cifs_async_readv - send an async write, and set up mid to handle result */
1749int
1750cifs_async_readv(struct cifs_readdata *rdata)
1751{
1752 int rc;
1753 READ_REQ *smb = NULL;
1754 int wct;
1755 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001756 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1757 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001758
Joe Perchesf96637b2013-05-04 22:12:25 -05001759 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1760 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001761
1762 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1763 wct = 12;
1764 else {
1765 wct = 10; /* old style read */
1766 if ((rdata->offset >> 32) > 0) {
1767 /* can not handle this big offset for old */
1768 return -EIO;
1769 }
1770 }
1771
1772 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1773 if (rc)
1774 return rc;
1775
1776 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1777 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1778
1779 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001780 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001781 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1782 if (wct == 12)
1783 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1784 smb->Remaining = 0;
1785 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1786 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1787 if (wct == 12)
1788 smb->ByteCount = 0;
1789 else {
1790 /* old style read */
1791 struct smb_com_readx_req *smbr =
1792 (struct smb_com_readx_req *)smb;
1793 smbr->ByteCount = 0;
1794 }
1795
1796 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001797 rdata->iov[0].iov_base = smb;
1798 rdata->iov[0].iov_len = 4;
1799 rdata->iov[1].iov_base = (char *)smb + 4;
1800 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001801
Jeff Layton6993f742012-05-16 07:13:17 -04001802 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001803 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08001804 cifs_readv_callback, NULL, rdata, 0, NULL);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001805
1806 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001807 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001808 else
1809 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001810
1811 cifs_small_buf_release(smb);
1812 return rc;
1813}
1814
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001816CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1817 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818{
1819 int rc = -EACCES;
1820 READ_REQ *pSMB = NULL;
1821 READ_RSP *pSMBr = NULL;
1822 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001823 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001824 int resp_buf_type = 0;
1825 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001826 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001827 __u32 pid = io_parms->pid;
1828 __u16 netfid = io_parms->netfid;
1829 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001830 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001831 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
Joe Perchesf96637b2013-05-04 22:12:25 -05001833 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001834 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001835 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001836 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001837 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001838 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001839 /* can not handle this big offset for old */
1840 return -EIO;
1841 }
1842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001845 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if (rc)
1847 return rc;
1848
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001849 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1850 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 /* tcon and ses pointer are checked in smb_init */
1853 if (tcon->ses->server == NULL)
1854 return -ECONNABORTED;
1855
Steve Frenchec637e32005-12-12 20:53:18 -08001856 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001858 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001859 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001860 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 pSMB->Remaining = 0;
1863 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1864 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001865 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001866 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1867 else {
1868 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001869 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001870 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001871 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001872 }
Steve Frenchec637e32005-12-12 20:53:18 -08001873
1874 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001875 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001876 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1877 CIFS_LOG_ERROR, &rsp_iov);
1878 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001879 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001880 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001882 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 } else {
1884 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1885 data_length = data_length << 16;
1886 data_length += le16_to_cpu(pSMBr->DataLength);
1887 *nbytes = data_length;
1888
1889 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001890 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001892 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001893 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 rc = -EIO;
1895 *nbytes = 0;
1896 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001897 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001898 le16_to_cpu(pSMBr->DataOffset);
1899/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001900 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001901 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001902 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001903 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001904 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 }
1906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
Steve French790fe572007-07-07 19:25:05 +00001908 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001909 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001910 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001911 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001912 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001913 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001914 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001915 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001916 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001917 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001918
1919 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 since file handle passed in no longer valid */
1921 return rc;
1922}
1923
Steve Frenchec637e32005-12-12 20:53:18 -08001924
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001926CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001927 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
1929 int rc = -EACCES;
1930 WRITE_REQ *pSMB = NULL;
1931 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001932 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 __u32 bytes_sent;
1934 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001935 __u32 pid = io_parms->pid;
1936 __u16 netfid = io_parms->netfid;
1937 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001938 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001939 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
Steve Frencha24e2d72010-04-03 17:20:21 +00001941 *nbytes = 0;
1942
Joe Perchesf96637b2013-05-04 22:12:25 -05001943 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001944 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001945 return -ECONNABORTED;
1946
Steve French790fe572007-07-07 19:25:05 +00001947 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001948 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001949 else {
Steve French1c955182005-08-30 20:58:07 -07001950 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001951 if ((offset >> 32) > 0) {
1952 /* can not handle big offset for old srv */
1953 return -EIO;
1954 }
1955 }
Steve French1c955182005-08-30 20:58:07 -07001956
1957 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 (void **) &pSMBr);
1959 if (rc)
1960 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001961
1962 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1963 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1964
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 /* tcon and ses pointer are checked in smb_init */
1966 if (tcon->ses->server == NULL)
1967 return -ECONNABORTED;
1968
1969 pSMB->AndXCommand = 0xFF; /* none */
1970 pSMB->Fid = netfid;
1971 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001972 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001973 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001974
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 pSMB->Reserved = 0xFFFFFFFF;
1976 pSMB->WriteMode = 0;
1977 pSMB->Remaining = 0;
1978
Steve French50c2f752007-07-13 00:33:32 +00001979 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 can send more if LARGE_WRITE_X capability returned by the server and if
1981 our buffer is big enough or if we convert to iovecs on socket writes
1982 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001983 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1985 } else {
1986 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1987 & ~0xFF;
1988 }
1989
1990 if (bytes_sent > count)
1991 bytes_sent = count;
1992 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001993 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001994 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001995 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001996 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 /* No buffer */
1998 cifs_buf_release(pSMB);
1999 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07002000 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00002001 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07002002 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00002003 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07002004 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00002005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
2007 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002008 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07002009
Steve French790fe572007-07-07 19:25:05 +00002010 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07002011 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00002012 else { /* old style write has byte count 4 bytes earlier
2013 so 4 bytes pad */
2014 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07002015 (struct smb_com_writex_req *)pSMB;
2016 pSMBW->ByteCount = cpu_to_le16(byte_count);
2017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
2019 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04002020 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002021 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002023 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 } else {
2025 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2026 *nbytes = (*nbytes) << 16;
2027 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302028
2029 /*
2030 * Mask off high 16 bits when bytes written as returned by the
2031 * server is greater than bytes requested by the client. Some
2032 * OS/2 servers are known to set incorrect CountHigh values.
2033 */
2034 if (*nbytes > count)
2035 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
2037
2038 cifs_buf_release(pSMB);
2039
Steve French50c2f752007-07-13 00:33:32 +00002040 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 since file handle passed in no longer valid */
2042
2043 return rc;
2044}
2045
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002046void
2047cifs_writedata_release(struct kref *refcount)
2048{
2049 struct cifs_writedata *wdata = container_of(refcount,
2050 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07002051#ifdef CONFIG_CIFS_SMB_DIRECT
2052 if (wdata->mr) {
2053 smbd_deregister_mr(wdata->mr);
2054 wdata->mr = NULL;
2055 }
2056#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002057
2058 if (wdata->cfile)
2059 cifsFileInfo_put(wdata->cfile);
2060
Long Li8e7360f2018-05-30 12:47:56 -07002061 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 kfree(wdata);
2063}
2064
2065/*
2066 * Write failed with a retryable error. Resend the write request. It's also
2067 * possible that the page was redirtied so re-clean the page.
2068 */
2069static void
2070cifs_writev_requeue(struct cifs_writedata *wdata)
2071{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002072 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00002073 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07002074 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002075 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002077 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
2078 i = 0;
2079 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002081 struct cifs_writedata *wdata2;
2082 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002083
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002084 wsize = server->ops->wp_retry_size(inode);
2085 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002086 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002087 if (!nr_pages) {
2088 rc = -ENOTSUPP;
2089 break;
2090 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002091 cur_len = nr_pages * PAGE_SIZE;
2092 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002093 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002094 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002095 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002096 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06002097 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002098
2099 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2100 if (!wdata2) {
2101 rc = -ENOMEM;
2102 break;
2103 }
2104
2105 for (j = 0; j < nr_pages; j++) {
2106 wdata2->pages[j] = wdata->pages[i + j];
2107 lock_page(wdata2->pages[j]);
2108 clear_page_dirty_for_io(wdata2->pages[j]);
2109 }
2110
2111 wdata2->sync_mode = wdata->sync_mode;
2112 wdata2->nr_pages = nr_pages;
2113 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002114 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002115 wdata2->tailsz = tailsz;
2116 wdata2->bytes = cur_len;
2117
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002118 rc = cifs_get_writable_file(CIFS_I(inode), false,
2119 &wdata2->cfile);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002120 if (!wdata2->cfile) {
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002121 cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
2122 rc);
2123 if (!is_retryable_error(rc))
2124 rc = -EBADF;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002125 } else {
2126 wdata2->pid = wdata2->cfile->pid;
2127 rc = server->ops->async_writev(wdata2,
2128 cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002129 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002130
2131 for (j = 0; j < nr_pages; j++) {
2132 unlock_page(wdata2->pages[j]);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002133 if (rc != 0 && !is_retryable_error(rc)) {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002134 SetPageError(wdata2->pages[j]);
2135 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002136 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002137 }
2138 }
2139
2140 if (rc) {
2141 kref_put(&wdata2->refcount, cifs_writedata_release);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002142 if (is_retryable_error(rc))
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002143 continue;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002144 i += nr_pages;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002145 break;
2146 }
2147
2148 rest_len -= cur_len;
2149 i += nr_pages;
2150 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002151
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002152 /* cleanup remaining pages from the original wdata */
2153 for (; i < wdata->nr_pages; i++) {
2154 SetPageError(wdata->pages[i]);
2155 end_page_writeback(wdata->pages[i]);
2156 put_page(wdata->pages[i]);
2157 }
2158
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002159 if (rc != 0 && !is_retryable_error(rc))
2160 mapping_set_error(inode->i_mapping, rc);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002161 kref_put(&wdata->refcount, cifs_writedata_release);
2162}
2163
Jeff Laytonc2e87642012-03-23 14:40:55 -04002164void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002165cifs_writev_complete(struct work_struct *work)
2166{
2167 struct cifs_writedata *wdata = container_of(work,
2168 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002169 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002170 int i = 0;
2171
2172 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002173 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002174 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002175 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002176 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2177 wdata->bytes);
2178 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2179 return cifs_writev_requeue(wdata);
2180
2181 for (i = 0; i < wdata->nr_pages; i++) {
2182 struct page *page = wdata->pages[i];
2183 if (wdata->result == -EAGAIN)
2184 __set_page_dirty_nobuffers(page);
2185 else if (wdata->result < 0)
2186 SetPageError(page);
2187 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002188 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002189 }
2190 if (wdata->result != -EAGAIN)
2191 mapping_set_error(inode->i_mapping, wdata->result);
2192 kref_put(&wdata->refcount, cifs_writedata_release);
2193}
2194
2195struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002196cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002197{
Long Li8e7360f2018-05-30 12:47:56 -07002198 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002199 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002200 if (pages)
2201 return cifs_writedata_direct_alloc(pages, complete);
2202
2203 return NULL;
2204}
2205
2206struct cifs_writedata *
2207cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2208{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002209 struct cifs_writedata *wdata;
2210
Long Li8e7360f2018-05-30 12:47:56 -07002211 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002212 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002213 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002214 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002215 INIT_LIST_HEAD(&wdata->list);
2216 init_completion(&wdata->done);
2217 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002218 }
2219 return wdata;
2220}
2221
2222/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002223 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002224 * workqueue completion task.
2225 */
2226static void
2227cifs_writev_callback(struct mid_q_entry *mid)
2228{
2229 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002230 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002231 unsigned int written;
2232 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002233 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002234
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002235 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002236 case MID_RESPONSE_RECEIVED:
2237 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2238 if (wdata->result != 0)
2239 break;
2240
2241 written = le16_to_cpu(smb->CountHigh);
2242 written <<= 16;
2243 written += le16_to_cpu(smb->Count);
2244 /*
2245 * Mask off high 16 bits when bytes written as returned
2246 * by the server is greater than bytes requested by the
2247 * client. OS/2 servers are known to set incorrect
2248 * CountHigh values.
2249 */
2250 if (written > wdata->bytes)
2251 written &= 0xFFFF;
2252
2253 if (written < wdata->bytes)
2254 wdata->result = -ENOSPC;
2255 else
2256 wdata->bytes = written;
2257 break;
2258 case MID_REQUEST_SUBMITTED:
2259 case MID_RETRY_NEEDED:
2260 wdata->result = -EAGAIN;
2261 break;
2262 default:
2263 wdata->result = -EIO;
2264 break;
2265 }
2266
Jeff Laytonda472fc2012-03-23 14:40:53 -04002267 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002268 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002269 add_credits(tcon->ses->server, &credits, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002270}
2271
2272/* cifs_async_writev - send an async write, and set up mid to handle result */
2273int
Steve French4a5c80d2014-02-07 20:45:12 -06002274cifs_async_writev(struct cifs_writedata *wdata,
2275 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002276{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002277 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002278 WRITE_REQ *smb = NULL;
2279 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002280 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002281 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002282 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002283
2284 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2285 wct = 14;
2286 } else {
2287 wct = 12;
2288 if (wdata->offset >> 32 > 0) {
2289 /* can not handle big offset for old srv */
2290 return -EIO;
2291 }
2292 }
2293
2294 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2295 if (rc)
2296 goto async_writev_out;
2297
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002298 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2299 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002300
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002301 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002302 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002303 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2304 if (wct == 14)
2305 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2306 smb->Reserved = 0xFFFFFFFF;
2307 smb->WriteMode = 0;
2308 smb->Remaining = 0;
2309
2310 smb->DataOffset =
2311 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2312
2313 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002314 iov[0].iov_len = 4;
2315 iov[0].iov_base = smb;
2316 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2317 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002318
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002319 rqst.rq_iov = iov;
2320 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002321 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002322 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002323 rqst.rq_npages = wdata->nr_pages;
2324 rqst.rq_pagesz = wdata->pagesz;
2325 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002326
Joe Perchesf96637b2013-05-04 22:12:25 -05002327 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2328 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002329
2330 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2331 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2332
2333 if (wct == 14) {
2334 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2335 put_bcc(wdata->bytes + 1, &smb->hdr);
2336 } else {
2337 /* wct == 12 */
2338 struct smb_com_writex_req *smbw =
2339 (struct smb_com_writex_req *)smb;
2340 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2341 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002342 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002343 }
2344
2345 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002346 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08002347 cifs_writev_callback, NULL, wdata, 0, NULL);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002348
2349 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002350 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002351 else
Steve French4a5c80d2014-02-07 20:45:12 -06002352 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002353
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002354async_writev_out:
2355 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002356 return rc;
2357}
2358
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002359int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002360CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002361 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
2363 int rc = -EACCES;
2364 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002365 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002366 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002367 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002368 __u32 pid = io_parms->pid;
2369 __u16 netfid = io_parms->netfid;
2370 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002371 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002372 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002373 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002375 *nbytes = 0;
2376
Joe Perchesf96637b2013-05-04 22:12:25 -05002377 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002378
Steve French4c3130e2008-12-09 00:28:16 +00002379 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002380 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002381 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002382 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002383 if ((offset >> 32) > 0) {
2384 /* can not handle big offset for old srv */
2385 return -EIO;
2386 }
2387 }
Steve French8cc64c62005-10-03 13:49:43 -07002388 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 if (rc)
2390 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002391
2392 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2393 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 /* tcon and ses pointer are checked in smb_init */
2396 if (tcon->ses->server == NULL)
2397 return -ECONNABORTED;
2398
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002399 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 pSMB->Fid = netfid;
2401 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002402 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002403 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 pSMB->Reserved = 0xFFFFFFFF;
2405 pSMB->WriteMode = 0;
2406 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002407
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002409 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Steve French3e844692005-10-03 13:37:24 -07002411 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2412 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002413 /* header + 1 byte pad */
2414 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002415 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002416 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002417 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002418 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002419 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002420 pSMB->ByteCount = cpu_to_le16(count + 1);
2421 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002422 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002423 (struct smb_com_writex_req *)pSMB;
2424 pSMBW->ByteCount = cpu_to_le16(count + 5);
2425 }
Steve French3e844692005-10-03 13:37:24 -07002426 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002427 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002428 iov[0].iov_len = smb_hdr_len + 4;
2429 else /* wct == 12 pad bigger by four bytes */
2430 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002431
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002432 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2433 &rsp_iov);
2434 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002435 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002437 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002438 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002439 /* presumably this can not happen, but best to be safe */
2440 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002441 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002442 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002443 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2444 *nbytes = (*nbytes) << 16;
2445 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302446
2447 /*
2448 * Mask off high 16 bits when bytes written as returned by the
2449 * server is greater than bytes requested by the client. OS/2
2450 * servers are known to set incorrect CountHigh values.
2451 */
2452 if (*nbytes > count)
2453 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002456 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
Steve French50c2f752007-07-13 00:33:32 +00002458 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 since file handle passed in no longer valid */
2460
2461 return rc;
2462}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002463
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002464int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2465 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002466 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2467{
2468 int rc = 0;
2469 LOCK_REQ *pSMB = NULL;
2470 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002471 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002472 int resp_buf_type;
2473 __u16 count;
2474
Joe Perchesf96637b2013-05-04 22:12:25 -05002475 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2476 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002477
2478 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2479 if (rc)
2480 return rc;
2481
2482 pSMB->Timeout = 0;
2483 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2484 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2485 pSMB->LockType = lock_type;
2486 pSMB->AndXCommand = 0xFF; /* none */
2487 pSMB->Fid = netfid; /* netfid stays le */
2488
2489 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2490 inc_rfc1001_len(pSMB, count);
2491 pSMB->ByteCount = cpu_to_le16(count);
2492
2493 iov[0].iov_base = (char *)pSMB;
2494 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2495 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2496 iov[1].iov_base = (char *)buf;
2497 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2498
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002499 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002500 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
2501 CIFS_NO_RSP_BUF, &rsp_iov);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002502 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002503 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002504 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002505
2506 return rc;
2507}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002510CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002511 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002513 const __u32 numLock, const __u8 lockType,
2514 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515{
2516 int rc = 0;
2517 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002518/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002520 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 __u16 count;
2522
Joe Perchesf96637b2013-05-04 22:12:25 -05002523 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2524 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002525 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2526
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 if (rc)
2528 return rc;
2529
Steve French790fe572007-07-07 19:25:05 +00002530 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002531 /* no response expected */
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002532 flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002534 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002535 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2537 } else {
2538 pSMB->Timeout = 0;
2539 }
2540
2541 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2542 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2543 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002544 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 pSMB->AndXCommand = 0xFF; /* none */
2546 pSMB->Fid = smb_file_id; /* netfid stays le */
2547
Steve French790fe572007-07-07 19:25:05 +00002548 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002549 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 /* BB where to store pid high? */
2551 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2552 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2553 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2554 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2555 count = sizeof(LOCKING_ANDX_RANGE);
2556 } else {
2557 /* oplock break */
2558 count = 0;
2559 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002560 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 pSMB->ByteCount = cpu_to_le16(count);
2562
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002563 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002564 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002565 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002566 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002567 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002568 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002569 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002570 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002571 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
Steve French50c2f752007-07-13 00:33:32 +00002573 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 since file handle passed in no longer valid */
2575 return rc;
2576}
2577
2578int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002579CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002580 const __u16 smb_file_id, const __u32 netpid,
2581 const loff_t start_offset, const __u64 len,
2582 struct file_lock *pLockData, const __u16 lock_type,
2583 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002584{
2585 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2586 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002587 struct cifs_posix_lock *parm_data;
2588 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002589 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002590 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002591 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002592 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002593 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002594 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002595
Joe Perchesf96637b2013-05-04 22:12:25 -05002596 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002597
Steve French08547b02006-02-28 22:39:25 +00002598 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2599
2600 if (rc)
2601 return rc;
2602
2603 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2604
Steve French50c2f752007-07-13 00:33:32 +00002605 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002606 pSMB->MaxSetupCount = 0;
2607 pSMB->Reserved = 0;
2608 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002609 pSMB->Reserved2 = 0;
2610 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2611 offset = param_offset + params;
2612
Steve French08547b02006-02-28 22:39:25 +00002613 count = sizeof(struct cifs_posix_lock);
2614 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002615 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002616 pSMB->SetupCount = 1;
2617 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002618 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002619 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2620 else
2621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2622 byte_count = 3 /* pad */ + params + count;
2623 pSMB->DataCount = cpu_to_le16(count);
2624 pSMB->ParameterCount = cpu_to_le16(params);
2625 pSMB->TotalDataCount = pSMB->DataCount;
2626 pSMB->TotalParameterCount = pSMB->ParameterCount;
2627 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002628 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002629 (((char *) &pSMB->hdr.Protocol) + offset);
2630
2631 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002632 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002633 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002634 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002635 pSMB->Timeout = cpu_to_le32(-1);
2636 } else
2637 pSMB->Timeout = 0;
2638
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002639 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002640 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002641 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002642
2643 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002644 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002645 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2646 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002647 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002648 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002649 if (waitFlag) {
2650 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2651 (struct smb_hdr *) pSMBr, &bytes_returned);
2652 } else {
Steve French133672e2007-11-13 22:41:37 +00002653 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002654 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002655 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002656 &resp_buf_type, timeout, &rsp_iov);
2657 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002658 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002659 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002660
Steve French08547b02006-02-28 22:39:25 +00002661 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002662 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002663 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002664 /* lock structure can be returned on get */
2665 __u16 data_offset;
2666 __u16 data_count;
2667 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002668
Jeff Layton820a8032011-05-04 08:05:26 -04002669 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002670 rc = -EIO; /* bad smb */
2671 goto plk_err_exit;
2672 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002673 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2674 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002675 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002676 rc = -EIO;
2677 goto plk_err_exit;
2678 }
2679 parm_data = (struct cifs_posix_lock *)
2680 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002681 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002682 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002683 else {
2684 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002685 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002686 pLockData->fl_type = F_RDLCK;
2687 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002688 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002689 pLockData->fl_type = F_WRLCK;
2690
Steve French5443d132011-03-13 05:08:25 +00002691 pLockData->fl_start = le64_to_cpu(parm_data->start);
2692 pLockData->fl_end = pLockData->fl_start +
2693 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002694 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002695 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002696 }
Steve French50c2f752007-07-13 00:33:32 +00002697
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002698plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002699 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002700
Steve French08547b02006-02-28 22:39:25 +00002701 /* Note: On -EAGAIN error only caller can retry on handle based calls
2702 since file handle passed in no longer valid */
2703
2704 return rc;
2705}
2706
2707
2708int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002709CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710{
2711 int rc = 0;
2712 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002713 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
2715/* do not retry on dead session on close */
2716 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002717 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return 0;
2719 if (rc)
2720 return rc;
2721
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002723 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002725 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002726 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002727 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002729 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002731 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 }
2733 }
2734
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002736 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 rc = 0;
2738
2739 return rc;
2740}
2741
2742int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002743CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002744{
2745 int rc = 0;
2746 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002747 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002748
2749 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2750 if (rc)
2751 return rc;
2752
2753 pSMB->FileID = (__u16) smb_file_id;
2754 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002755 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002756 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002757 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002758 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002759 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002760
2761 return rc;
2762}
2763
2764int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002765CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002766 const char *from_name, const char *to_name,
2767 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768{
2769 int rc = 0;
2770 RENAME_REQ *pSMB = NULL;
2771 RENAME_RSP *pSMBr = NULL;
2772 int bytes_returned;
2773 int name_len, name_len2;
2774 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002775 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Joe Perchesf96637b2013-05-04 22:12:25 -05002777 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778renameRetry:
2779 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2780 (void **) &pSMBr);
2781 if (rc)
2782 return rc;
2783
2784 pSMB->BufferFormat = 0x04;
2785 pSMB->SearchAttributes =
2786 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2787 ATTR_DIRECTORY);
2788
2789 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002790 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2791 from_name, PATH_MAX,
2792 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 name_len++; /* trailing null */
2794 name_len *= 2;
2795 pSMB->OldFileName[name_len] = 0x04; /* pad */
2796 /* protocol requires ASCII signature byte on Unicode string */
2797 pSMB->OldFileName[name_len + 1] = 0x00;
2798 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002799 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002800 to_name, PATH_MAX, cifs_sb->local_nls,
2801 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2803 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002804 } else {
2805 name_len = copy_path_name(pSMB->OldFileName, from_name);
2806 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 name_len2++; /* signature byte */
2809 }
2810
2811 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002812 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 pSMB->ByteCount = cpu_to_le16(count);
2814
2815 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2816 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002817 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002818 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002819 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 cifs_buf_release(pSMB);
2822
2823 if (rc == -EAGAIN)
2824 goto renameRetry;
2825
2826 return rc;
2827}
2828
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002829int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002830 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002831 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832{
2833 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2834 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002835 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 char *data_offset;
2837 char dummy_string[30];
2838 int rc = 0;
2839 int bytes_returned = 0;
2840 int len_of_str;
2841 __u16 params, param_offset, offset, count, byte_count;
2842
Joe Perchesf96637b2013-05-04 22:12:25 -05002843 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2845 (void **) &pSMBr);
2846 if (rc)
2847 return rc;
2848
2849 params = 6;
2850 pSMB->MaxSetupCount = 0;
2851 pSMB->Reserved = 0;
2852 pSMB->Flags = 0;
2853 pSMB->Timeout = 0;
2854 pSMB->Reserved2 = 0;
2855 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2856 offset = param_offset + params;
2857
2858 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2859 rename_info = (struct set_file_rename *) data_offset;
2860 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002861 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 pSMB->SetupCount = 1;
2863 pSMB->Reserved3 = 0;
2864 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2865 byte_count = 3 /* pad */ + params;
2866 pSMB->ParameterCount = cpu_to_le16(params);
2867 pSMB->TotalParameterCount = pSMB->ParameterCount;
2868 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2869 pSMB->DataOffset = cpu_to_le16(offset);
2870 /* construct random name ".cifs_tmp<inodenum><mid>" */
2871 rename_info->overwrite = cpu_to_le32(1);
2872 rename_info->root_fid = 0;
2873 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002874 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002875 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002876 len_of_str =
2877 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002878 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002880 len_of_str =
2881 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002882 target_name, PATH_MAX, nls_codepage,
2883 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 }
2885 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002886 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 byte_count += count;
2888 pSMB->DataCount = cpu_to_le16(count);
2889 pSMB->TotalDataCount = pSMB->DataCount;
2890 pSMB->Fid = netfid;
2891 pSMB->InformationLevel =
2892 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2893 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002894 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 pSMB->ByteCount = cpu_to_le16(byte_count);
2896 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002898 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002899 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002900 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2901 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 cifs_buf_release(pSMB);
2904
2905 /* Note: On -EAGAIN error only caller can retry on handle based calls
2906 since file handle passed in no longer valid */
2907
2908 return rc;
2909}
2910
2911int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002912CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2913 const char *fromName, const __u16 target_tid, const char *toName,
2914 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916 int rc = 0;
2917 COPY_REQ *pSMB = NULL;
2918 COPY_RSP *pSMBr = NULL;
2919 int bytes_returned;
2920 int name_len, name_len2;
2921 __u16 count;
2922
Joe Perchesf96637b2013-05-04 22:12:25 -05002923 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924copyRetry:
2925 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2926 (void **) &pSMBr);
2927 if (rc)
2928 return rc;
2929
2930 pSMB->BufferFormat = 0x04;
2931 pSMB->Tid2 = target_tid;
2932
2933 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2934
2935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002936 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2937 fromName, PATH_MAX, nls_codepage,
2938 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 name_len++; /* trailing null */
2940 name_len *= 2;
2941 pSMB->OldFileName[name_len] = 0x04; /* pad */
2942 /* protocol requires ASCII signature byte on Unicode string */
2943 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002944 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002945 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2946 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2948 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002949 } else {
2950 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002952 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 name_len2++; /* signature byte */
2954 }
2955
2956 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002957 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 pSMB->ByteCount = cpu_to_le16(count);
2959
2960 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2962 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002963 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2964 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 }
Steve French0d817bc2008-05-22 02:02:03 +00002966 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
2968 if (rc == -EAGAIN)
2969 goto copyRetry;
2970
2971 return rc;
2972}
2973
2974int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002975CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002977 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978{
2979 TRANSACTION2_SPI_REQ *pSMB = NULL;
2980 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2981 char *data_offset;
2982 int name_len;
2983 int name_len_target;
2984 int rc = 0;
2985 int bytes_returned = 0;
2986 __u16 params, param_offset, offset, byte_count;
2987
Joe Perchesf96637b2013-05-04 22:12:25 -05002988 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989createSymLinkRetry:
2990 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2991 (void **) &pSMBr);
2992 if (rc)
2993 return rc;
2994
2995 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2996 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002997 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2998 /* find define for this maxpathcomponent */
2999 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 name_len++; /* trailing null */
3001 name_len *= 2;
3002
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003003 } else {
3004 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 }
3006 params = 6 + name_len;
3007 pSMB->MaxSetupCount = 0;
3008 pSMB->Reserved = 0;
3009 pSMB->Flags = 0;
3010 pSMB->Timeout = 0;
3011 pSMB->Reserved2 = 0;
3012 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003013 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 offset = param_offset + params;
3015
3016 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3017 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3018 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003019 cifsConvertToUTF16((__le16 *) data_offset, toName,
3020 /* find define for this maxpathcomponent */
3021 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 name_len_target++; /* trailing null */
3023 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003024 } else {
3025 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 }
3027
3028 pSMB->MaxParameterCount = cpu_to_le16(2);
3029 /* BB find exact max on data count below from sess */
3030 pSMB->MaxDataCount = cpu_to_le16(1000);
3031 pSMB->SetupCount = 1;
3032 pSMB->Reserved3 = 0;
3033 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3034 byte_count = 3 /* pad */ + params + name_len_target;
3035 pSMB->DataCount = cpu_to_le16(name_len_target);
3036 pSMB->ParameterCount = cpu_to_le16(params);
3037 pSMB->TotalDataCount = pSMB->DataCount;
3038 pSMB->TotalParameterCount = pSMB->ParameterCount;
3039 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3040 pSMB->DataOffset = cpu_to_le16(offset);
3041 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
3042 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003043 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 pSMB->ByteCount = cpu_to_le16(byte_count);
3045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003047 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003048 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003049 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
3050 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051
Steve French0d817bc2008-05-22 02:02:03 +00003052 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053
3054 if (rc == -EAGAIN)
3055 goto createSymLinkRetry;
3056
3057 return rc;
3058}
3059
3060int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003061CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07003063 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064{
3065 TRANSACTION2_SPI_REQ *pSMB = NULL;
3066 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3067 char *data_offset;
3068 int name_len;
3069 int name_len_target;
3070 int rc = 0;
3071 int bytes_returned = 0;
3072 __u16 params, param_offset, offset, byte_count;
3073
Joe Perchesf96637b2013-05-04 22:12:25 -05003074 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075createHardLinkRetry:
3076 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3077 (void **) &pSMBr);
3078 if (rc)
3079 return rc;
3080
3081 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06003082 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
3083 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 name_len++; /* trailing null */
3085 name_len *= 2;
3086
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003087 } else {
3088 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 }
3090 params = 6 + name_len;
3091 pSMB->MaxSetupCount = 0;
3092 pSMB->Reserved = 0;
3093 pSMB->Flags = 0;
3094 pSMB->Timeout = 0;
3095 pSMB->Reserved2 = 0;
3096 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003097 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 offset = param_offset + params;
3099
3100 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3101 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3102 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003103 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3104 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 name_len_target++; /* trailing null */
3106 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003107 } else {
3108 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 }
3110
3111 pSMB->MaxParameterCount = cpu_to_le16(2);
3112 /* BB find exact max on data count below from sess*/
3113 pSMB->MaxDataCount = cpu_to_le16(1000);
3114 pSMB->SetupCount = 1;
3115 pSMB->Reserved3 = 0;
3116 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3117 byte_count = 3 /* pad */ + params + name_len_target;
3118 pSMB->ParameterCount = cpu_to_le16(params);
3119 pSMB->TotalParameterCount = pSMB->ParameterCount;
3120 pSMB->DataCount = cpu_to_le16(name_len_target);
3121 pSMB->TotalDataCount = pSMB->DataCount;
3122 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3123 pSMB->DataOffset = cpu_to_le16(offset);
3124 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3125 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003126 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 pSMB->ByteCount = cpu_to_le16(byte_count);
3128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003130 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003131 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003132 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3133 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
3135 cifs_buf_release(pSMB);
3136 if (rc == -EAGAIN)
3137 goto createHardLinkRetry;
3138
3139 return rc;
3140}
3141
3142int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003143CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003144 const char *from_name, const char *to_name,
3145 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146{
3147 int rc = 0;
3148 NT_RENAME_REQ *pSMB = NULL;
3149 RENAME_RSP *pSMBr = NULL;
3150 int bytes_returned;
3151 int name_len, name_len2;
3152 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003153 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154
Joe Perchesf96637b2013-05-04 22:12:25 -05003155 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156winCreateHardLinkRetry:
3157
3158 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3159 (void **) &pSMBr);
3160 if (rc)
3161 return rc;
3162
3163 pSMB->SearchAttributes =
3164 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3165 ATTR_DIRECTORY);
3166 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3167 pSMB->ClusterCount = 0;
3168
3169 pSMB->BufferFormat = 0x04;
3170
3171 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3172 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003173 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3174 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 name_len++; /* trailing null */
3176 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003177
3178 /* protocol specifies ASCII buffer format (0x04) for unicode */
3179 pSMB->OldFileName[name_len] = 0x04;
3180 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003182 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003183 to_name, PATH_MAX, cifs_sb->local_nls,
3184 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3186 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003187 } else {
3188 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003190 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 name_len2++; /* signature byte */
3192 }
3193
3194 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003195 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 pSMB->ByteCount = cpu_to_le16(count);
3197
3198 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3199 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003200 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003201 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003202 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003203
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 cifs_buf_release(pSMB);
3205 if (rc == -EAGAIN)
3206 goto winCreateHardLinkRetry;
3207
3208 return rc;
3209}
3210
3211int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003212CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003213 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003214 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215{
3216/* SMB_QUERY_FILE_UNIX_LINK */
3217 TRANSACTION2_QPI_REQ *pSMB = NULL;
3218 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3219 int rc = 0;
3220 int bytes_returned;
3221 int name_len;
3222 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003223 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
Joe Perchesf96637b2013-05-04 22:12:25 -05003225 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226
3227querySymLinkRetry:
3228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3229 (void **) &pSMBr);
3230 if (rc)
3231 return rc;
3232
3233 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3234 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003235 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3236 searchName, PATH_MAX, nls_codepage,
3237 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 name_len++; /* trailing null */
3239 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003240 } else {
3241 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 }
3243
3244 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3245 pSMB->TotalDataCount = 0;
3246 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003247 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 pSMB->MaxSetupCount = 0;
3249 pSMB->Reserved = 0;
3250 pSMB->Flags = 0;
3251 pSMB->Timeout = 0;
3252 pSMB->Reserved2 = 0;
3253 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003254 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 pSMB->DataCount = 0;
3256 pSMB->DataOffset = 0;
3257 pSMB->SetupCount = 1;
3258 pSMB->Reserved3 = 0;
3259 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3260 byte_count = params + 1 /* pad */ ;
3261 pSMB->TotalParameterCount = cpu_to_le16(params);
3262 pSMB->ParameterCount = pSMB->TotalParameterCount;
3263 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3264 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003265 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 pSMB->ByteCount = cpu_to_le16(byte_count);
3267
3268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3269 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3270 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003271 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 } else {
3273 /* decode response */
3274
3275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003277 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003278 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003280 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003281 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
Jeff Layton460b9692009-04-30 07:17:56 -04003283 data_start = ((char *) &pSMBr->hdr.Protocol) +
3284 le16_to_cpu(pSMBr->t2.DataOffset);
3285
Steve French0e0d2cf2009-05-01 05:27:32 +00003286 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3287 is_unicode = true;
3288 else
3289 is_unicode = false;
3290
Steve French737b7582005-04-28 22:41:06 -07003291 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003292 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3293 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003294 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003295 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 }
3297 }
3298 cifs_buf_release(pSMB);
3299 if (rc == -EAGAIN)
3300 goto querySymLinkRetry;
3301 return rc;
3302}
3303
Steve Frenchc52a95542011-02-24 06:16:22 +00003304/*
3305 * Recent Windows versions now create symlinks more frequently
3306 * and they use the "reparse point" mechanism below. We can of course
3307 * do symlinks nicely to Samba and other servers which support the
3308 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3309 * "MF" symlinks optionally, but for recent Windows we really need to
3310 * reenable the code below and fix the cifs_symlink callers to handle this.
3311 * In the interim this code has been moved to its own config option so
3312 * it is not compiled in by default until callers fixed up and more tested.
3313 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003315CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3316 __u16 fid, char **symlinkinfo,
3317 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318{
3319 int rc = 0;
3320 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003321 struct smb_com_transaction_ioctl_req *pSMB;
3322 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003323 bool is_unicode;
3324 unsigned int sub_len;
3325 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003326 struct reparse_symlink_data *reparse_buf;
3327 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003328 __u32 data_offset, data_count;
3329 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003331 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3333 (void **) &pSMBr);
3334 if (rc)
3335 return rc;
3336
3337 pSMB->TotalParameterCount = 0 ;
3338 pSMB->TotalDataCount = 0;
3339 pSMB->MaxParameterCount = cpu_to_le32(2);
3340 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003341 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 pSMB->MaxSetupCount = 4;
3343 pSMB->Reserved = 0;
3344 pSMB->ParameterOffset = 0;
3345 pSMB->DataCount = 0;
3346 pSMB->DataOffset = 0;
3347 pSMB->SetupCount = 4;
3348 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3349 pSMB->ParameterCount = pSMB->TotalParameterCount;
3350 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3351 pSMB->IsFsctl = 1; /* FSCTL */
3352 pSMB->IsRootFlag = 0;
3353 pSMB->Fid = fid; /* file handle always le */
3354 pSMB->ByteCount = 0;
3355
3356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3358 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003359 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003360 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 }
Steve French989c7e52009-05-02 05:32:20 +00003362
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003363 data_offset = le32_to_cpu(pSMBr->DataOffset);
3364 data_count = le32_to_cpu(pSMBr->DataCount);
3365 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3366 /* BB also check enough total bytes returned */
3367 rc = -EIO; /* bad smb */
3368 goto qreparse_out;
3369 }
3370 if (!data_count || (data_count > 2048)) {
3371 rc = -EIO;
3372 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3373 goto qreparse_out;
3374 }
3375 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003376 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003377 ((char *)&pSMBr->hdr.Protocol + data_offset);
3378 if ((char *)reparse_buf >= end_of_smb) {
3379 rc = -EIO;
3380 goto qreparse_out;
3381 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003382 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3383 cifs_dbg(FYI, "NFS style reparse tag\n");
3384 posix_buf = (struct reparse_posix_data *)reparse_buf;
3385
3386 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3387 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3388 le64_to_cpu(posix_buf->InodeType));
3389 rc = -EOPNOTSUPP;
3390 goto qreparse_out;
3391 }
3392 is_unicode = true;
3393 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3394 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3395 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3396 rc = -EIO;
3397 goto qreparse_out;
3398 }
3399 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3400 sub_len, is_unicode, nls_codepage);
3401 goto qreparse_out;
3402 } else if (reparse_buf->ReparseTag !=
3403 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3404 rc = -EOPNOTSUPP;
3405 goto qreparse_out;
3406 }
3407
3408 /* Reparse tag is NTFS symlink */
3409 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3410 reparse_buf->PathBuffer;
3411 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3412 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003413 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3414 rc = -EIO;
3415 goto qreparse_out;
3416 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003417 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3418 is_unicode = true;
3419 else
3420 is_unicode = false;
3421
3422 /* BB FIXME investigate remapping reserved chars here */
3423 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3424 nls_codepage);
3425 if (!*symlinkinfo)
3426 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003428 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003430 /*
3431 * Note: On -EAGAIN error only caller can retry on handle based calls
3432 * since file handle passed in no longer valid.
3433 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 return rc;
3435}
3436
Steve Frenchc7f508a2013-10-14 15:27:32 -05003437int
3438CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3439 __u16 fid)
3440{
3441 int rc = 0;
3442 int bytes_returned;
3443 struct smb_com_transaction_compr_ioctl_req *pSMB;
3444 struct smb_com_transaction_ioctl_rsp *pSMBr;
3445
3446 cifs_dbg(FYI, "Set compression for %u\n", fid);
3447 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3448 (void **) &pSMBr);
3449 if (rc)
3450 return rc;
3451
3452 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3453
3454 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003455 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003456 pSMB->MaxParameterCount = 0;
3457 pSMB->MaxDataCount = 0;
3458 pSMB->MaxSetupCount = 4;
3459 pSMB->Reserved = 0;
3460 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003461 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003462 pSMB->DataOffset =
3463 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3464 compression_state) - 4); /* 84 */
3465 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003466 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003467 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003468 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003469 pSMB->IsFsctl = 1; /* FSCTL */
3470 pSMB->IsRootFlag = 0;
3471 pSMB->Fid = fid; /* file handle always le */
3472 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003473 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003474 inc_rfc1001_len(pSMB, 5);
3475
3476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3477 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3478 if (rc)
3479 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3480
3481 cifs_buf_release(pSMB);
3482
3483 /*
3484 * Note: On -EAGAIN error only caller can retry on handle based calls
3485 * since file handle passed in no longer valid.
3486 */
3487 return rc;
3488}
3489
3490
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491#ifdef CONFIG_CIFS_POSIX
3492
3493/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003494static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003495 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496{
3497 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003498 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3499 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3500 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003501/*
3502 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3503 ace->e_perm, ace->e_tag, ace->e_id);
3504*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
3506 return;
3507}
3508
3509/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003510static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3511 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512{
3513 int size = 0;
3514 int i;
3515 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003516 struct cifs_posix_ace *pACE;
3517 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003518 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
3520 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3521 return -EOPNOTSUPP;
3522
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003523 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 count = le16_to_cpu(cifs_acl->access_entry_count);
3525 pACE = &cifs_acl->ace_array[0];
3526 size = sizeof(struct cifs_posix_acl);
3527 size += sizeof(struct cifs_posix_ace) * count;
3528 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003529 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003530 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3531 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 return -EINVAL;
3533 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003534 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 count = le16_to_cpu(cifs_acl->access_entry_count);
3536 size = sizeof(struct cifs_posix_acl);
3537 size += sizeof(struct cifs_posix_ace) * count;
3538/* skip past access ACEs to get to default ACEs */
3539 pACE = &cifs_acl->ace_array[count];
3540 count = le16_to_cpu(cifs_acl->default_entry_count);
3541 size += sizeof(struct cifs_posix_ace) * count;
3542 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003543 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 return -EINVAL;
3545 } else {
3546 /* illegal type */
3547 return -EINVAL;
3548 }
3549
3550 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003551 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003552 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003553 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 return -ERANGE;
3555 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003556 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3557
Steve Frenchff7feac2005-11-15 16:45:16 -08003558 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003559 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003560 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003561 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 }
3563 }
3564 return size;
3565}
3566
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303567static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003568 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569{
Steve Frenchff7feac2005-11-15 16:45:16 -08003570 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3571 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003573 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 /* Probably no need to le convert -1 on any arch but can not hurt */
3575 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003576 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003577 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003578/*
3579 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3580 ace->e_perm, ace->e_tag, ace->e_id);
3581*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582}
3583
3584/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003585static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3586 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587{
3588 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003589 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003590 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003591 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 int count;
3593 int i;
3594
Steve French790fe572007-07-07 19:25:05 +00003595 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 return 0;
3597
3598 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003599 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3600 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003601 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003602 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3603 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 return 0;
3605 }
3606 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003607 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003608 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003609 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003610 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003611 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003612 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003613 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003614 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 return 0;
3616 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303617 for (i = 0; i < count; i++)
3618 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003619 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3621 rc += sizeof(struct cifs_posix_acl);
3622 /* BB add check to make sure ACL does not overflow SMB */
3623 }
3624 return rc;
3625}
3626
3627int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003628CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003629 const unsigned char *searchName,
3630 char *acl_inf, const int buflen, const int acl_type,
3631 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632{
3633/* SMB_QUERY_POSIX_ACL */
3634 TRANSACTION2_QPI_REQ *pSMB = NULL;
3635 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3636 int rc = 0;
3637 int bytes_returned;
3638 int name_len;
3639 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003640
Joe Perchesf96637b2013-05-04 22:12:25 -05003641 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642
3643queryAclRetry:
3644 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3645 (void **) &pSMBr);
3646 if (rc)
3647 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003648
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3650 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003651 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3652 searchName, PATH_MAX, nls_codepage,
3653 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 name_len++; /* trailing null */
3655 name_len *= 2;
3656 pSMB->FileName[name_len] = 0;
3657 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003658 } else {
3659 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 }
3661
3662 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3663 pSMB->TotalDataCount = 0;
3664 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003665 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 pSMB->MaxDataCount = cpu_to_le16(4000);
3667 pSMB->MaxSetupCount = 0;
3668 pSMB->Reserved = 0;
3669 pSMB->Flags = 0;
3670 pSMB->Timeout = 0;
3671 pSMB->Reserved2 = 0;
3672 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003673 offsetof(struct smb_com_transaction2_qpi_req,
3674 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 pSMB->DataCount = 0;
3676 pSMB->DataOffset = 0;
3677 pSMB->SetupCount = 1;
3678 pSMB->Reserved3 = 0;
3679 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3680 byte_count = params + 1 /* pad */ ;
3681 pSMB->TotalParameterCount = cpu_to_le16(params);
3682 pSMB->ParameterCount = pSMB->TotalParameterCount;
3683 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3684 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003685 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 pSMB->ByteCount = cpu_to_le16(byte_count);
3687
3688 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3689 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003690 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003692 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 } else {
3694 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003695
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003698 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 rc = -EIO; /* bad smb */
3700 else {
3701 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3702 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3703 rc = cifs_copy_posix_acl(acl_inf,
3704 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003705 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 }
3707 }
3708 cifs_buf_release(pSMB);
3709 if (rc == -EAGAIN)
3710 goto queryAclRetry;
3711 return rc;
3712}
3713
3714int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003715CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003716 const unsigned char *fileName,
3717 const char *local_acl, const int buflen,
3718 const int acl_type,
3719 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720{
3721 struct smb_com_transaction2_spi_req *pSMB = NULL;
3722 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3723 char *parm_data;
3724 int name_len;
3725 int rc = 0;
3726 int bytes_returned = 0;
3727 __u16 params, byte_count, data_count, param_offset, offset;
3728
Joe Perchesf96637b2013-05-04 22:12:25 -05003729 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730setAclRetry:
3731 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003732 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 if (rc)
3734 return rc;
3735 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3736 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003737 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3738 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 name_len++; /* trailing null */
3740 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003741 } else {
3742 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 }
3744 params = 6 + name_len;
3745 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003746 /* BB find max SMB size from sess */
3747 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 pSMB->MaxSetupCount = 0;
3749 pSMB->Reserved = 0;
3750 pSMB->Flags = 0;
3751 pSMB->Timeout = 0;
3752 pSMB->Reserved2 = 0;
3753 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003754 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 offset = param_offset + params;
3756 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3757 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3758
3759 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003760 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
Steve French790fe572007-07-07 19:25:05 +00003762 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 rc = -EOPNOTSUPP;
3764 goto setACLerrorExit;
3765 }
3766 pSMB->DataOffset = cpu_to_le16(offset);
3767 pSMB->SetupCount = 1;
3768 pSMB->Reserved3 = 0;
3769 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3770 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3771 byte_count = 3 /* pad */ + params + data_count;
3772 pSMB->DataCount = cpu_to_le16(data_count);
3773 pSMB->TotalDataCount = pSMB->DataCount;
3774 pSMB->ParameterCount = cpu_to_le16(params);
3775 pSMB->TotalParameterCount = pSMB->ParameterCount;
3776 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003777 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 pSMB->ByteCount = cpu_to_le16(byte_count);
3779 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003780 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003781 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003782 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
3784setACLerrorExit:
3785 cifs_buf_release(pSMB);
3786 if (rc == -EAGAIN)
3787 goto setAclRetry;
3788 return rc;
3789}
3790
Steve Frenchf654bac2005-04-28 22:41:04 -07003791/* BB fix tabs in this function FIXME BB */
3792int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003793CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003794 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003795{
Steve French50c2f752007-07-13 00:33:32 +00003796 int rc = 0;
3797 struct smb_t2_qfi_req *pSMB = NULL;
3798 struct smb_t2_qfi_rsp *pSMBr = NULL;
3799 int bytes_returned;
3800 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003801
Joe Perchesf96637b2013-05-04 22:12:25 -05003802 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003803 if (tcon == NULL)
3804 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003805
3806GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003807 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3808 (void **) &pSMBr);
3809 if (rc)
3810 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003811
Steve Frenchad7a2922008-02-07 23:25:02 +00003812 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003813 pSMB->t2.TotalDataCount = 0;
3814 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3815 /* BB find exact max data count below from sess structure BB */
3816 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3817 pSMB->t2.MaxSetupCount = 0;
3818 pSMB->t2.Reserved = 0;
3819 pSMB->t2.Flags = 0;
3820 pSMB->t2.Timeout = 0;
3821 pSMB->t2.Reserved2 = 0;
3822 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3823 Fid) - 4);
3824 pSMB->t2.DataCount = 0;
3825 pSMB->t2.DataOffset = 0;
3826 pSMB->t2.SetupCount = 1;
3827 pSMB->t2.Reserved3 = 0;
3828 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3829 byte_count = params + 1 /* pad */ ;
3830 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3831 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3832 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3833 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003834 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003835 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003836 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003837
Steve French790fe572007-07-07 19:25:05 +00003838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3840 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003841 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003842 } else {
3843 /* decode response */
3844 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003845 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003846 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003847 /* If rc should we check for EOPNOSUPP and
3848 disable the srvino flag? or in caller? */
3849 rc = -EIO; /* bad smb */
3850 else {
3851 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3852 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3853 struct file_chattr_info *pfinfo;
3854 /* BB Do we need a cast or hash here ? */
3855 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003856 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003857 rc = -EIO;
3858 goto GetExtAttrOut;
3859 }
3860 pfinfo = (struct file_chattr_info *)
3861 (data_offset + (char *) &pSMBr->hdr.Protocol);
3862 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003863 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003864 }
3865 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003866GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003867 cifs_buf_release(pSMB);
3868 if (rc == -EAGAIN)
3869 goto GetExtAttrRetry;
3870 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003871}
3872
Steve Frenchf654bac2005-04-28 22:41:04 -07003873#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874
Jeff Layton79df1ba2010-12-06 12:52:08 -05003875/*
3876 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3877 * all NT TRANSACTS that we init here have total parm and data under about 400
3878 * bytes (to fit in small cifs buffer size), which is the case so far, it
3879 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3880 * returned setup area) and MaxParameterCount (returned parms size) must be set
3881 * by caller
3882 */
3883static int
3884smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003885 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003886 void **ret_buf)
3887{
3888 int rc;
3889 __u32 temp_offset;
3890 struct smb_com_ntransact_req *pSMB;
3891
3892 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3893 (void **)&pSMB);
3894 if (rc)
3895 return rc;
3896 *ret_buf = (void *)pSMB;
3897 pSMB->Reserved = 0;
3898 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3899 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003900 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003901 pSMB->ParameterCount = pSMB->TotalParameterCount;
3902 pSMB->DataCount = pSMB->TotalDataCount;
3903 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3904 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3905 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3906 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3907 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3908 pSMB->SubCommand = cpu_to_le16(sub_command);
3909 return 0;
3910}
3911
3912static int
3913validate_ntransact(char *buf, char **ppparm, char **ppdata,
3914 __u32 *pparmlen, __u32 *pdatalen)
3915{
3916 char *end_of_smb;
3917 __u32 data_count, data_offset, parm_count, parm_offset;
3918 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003919 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003920
3921 *pdatalen = 0;
3922 *pparmlen = 0;
3923
3924 if (buf == NULL)
3925 return -EINVAL;
3926
3927 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3928
Jeff Layton820a8032011-05-04 08:05:26 -04003929 bcc = get_bcc(&pSMBr->hdr);
3930 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003931 (char *)&pSMBr->ByteCount;
3932
3933 data_offset = le32_to_cpu(pSMBr->DataOffset);
3934 data_count = le32_to_cpu(pSMBr->DataCount);
3935 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3936 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3937
3938 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3939 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3940
3941 /* should we also check that parm and data areas do not overlap? */
3942 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003943 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003944 return -EINVAL;
3945 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003946 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003947 return -EINVAL;
3948 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003949 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003950 return -EINVAL;
3951 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003952 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3953 *ppdata, data_count, (data_count + *ppdata),
3954 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003955 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003956 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003957 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003958 return -EINVAL;
3959 }
3960 *pdatalen = data_count;
3961 *pparmlen = parm_count;
3962 return 0;
3963}
3964
Steve French0a4b92c2006-01-12 15:44:21 -08003965/* Get Security Descriptor (by handle) from remote server for a file or dir */
3966int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003967CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003968 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003969{
3970 int rc = 0;
3971 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003972 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003973 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003974 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003975
Joe Perchesf96637b2013-05-04 22:12:25 -05003976 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003977
Steve French630f3f0c2007-10-25 21:17:17 +00003978 *pbuflen = 0;
3979 *acl_inf = NULL;
3980
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003981 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003982 8 /* parm len */, tcon, (void **) &pSMB);
3983 if (rc)
3984 return rc;
3985
3986 pSMB->MaxParameterCount = cpu_to_le32(4);
3987 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3988 pSMB->MaxSetupCount = 0;
3989 pSMB->Fid = fid; /* file handle always le */
3990 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3991 CIFS_ACL_DACL);
3992 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003993 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003994 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003995 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003996
Steve Frencha761ac52007-10-18 21:45:27 +00003997 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003998 0, &rsp_iov);
3999 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004000 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08004001 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004002 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08004003 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00004004 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00004005 __u32 parm_len;
4006 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00004007 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00004008 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08004009
4010/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004011 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00004012 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00004013 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08004014 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004015 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08004016
Joe Perchesf96637b2013-05-04 22:12:25 -05004017 cifs_dbg(FYI, "smb %p parm %p data %p\n",
4018 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08004019
4020 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
4021 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00004022 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08004023 goto qsec_out;
4024 }
4025
4026/* BB check that data area is minimum length and as big as acl_len */
4027
Steve Frenchaf6f4612007-10-16 18:40:37 +00004028 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00004029 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004030 cifs_dbg(VFS, "acl length %d does not match %d\n",
4031 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00004032 if (*pbuflen > acl_len)
4033 *pbuflen = acl_len;
4034 }
Steve French0a4b92c2006-01-12 15:44:21 -08004035
Steve French630f3f0c2007-10-25 21:17:17 +00004036 /* check if buffer is big enough for the acl
4037 header followed by the smallest SID */
4038 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
4039 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004040 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00004041 rc = -EINVAL;
4042 *pbuflen = 0;
4043 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02004044 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00004045 if (*acl_inf == NULL) {
4046 *pbuflen = 0;
4047 rc = -ENOMEM;
4048 }
Steve French630f3f0c2007-10-25 21:17:17 +00004049 }
Steve French0a4b92c2006-01-12 15:44:21 -08004050 }
4051qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004052 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08004053 return rc;
4054}
Steve French97837582007-12-31 07:47:21 +00004055
4056int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004057CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004058 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00004059{
4060 __u16 byte_count, param_count, data_count, param_offset, data_offset;
4061 int rc = 0;
4062 int bytes_returned = 0;
4063 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004064 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00004065
4066setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004067 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00004068 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004069 return rc;
Steve French97837582007-12-31 07:47:21 +00004070
4071 pSMB->MaxSetupCount = 0;
4072 pSMB->Reserved = 0;
4073
4074 param_count = 8;
4075 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
4076 data_count = acllen;
4077 data_offset = param_offset + param_count;
4078 byte_count = 3 /* pad */ + param_count;
4079
4080 pSMB->DataCount = cpu_to_le32(data_count);
4081 pSMB->TotalDataCount = pSMB->DataCount;
4082 pSMB->MaxParameterCount = cpu_to_le32(4);
4083 pSMB->MaxDataCount = cpu_to_le32(16384);
4084 pSMB->ParameterCount = cpu_to_le32(param_count);
4085 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4086 pSMB->TotalParameterCount = pSMB->ParameterCount;
4087 pSMB->DataOffset = cpu_to_le32(data_offset);
4088 pSMB->SetupCount = 0;
4089 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4090 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4091
4092 pSMB->Fid = fid; /* file handle always le */
4093 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004094 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004095
4096 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004097 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4098 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004099 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004100 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004101 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004102
4103 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4104 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4105
Joe Perchesf96637b2013-05-04 22:12:25 -05004106 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4107 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004108 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004109 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004110 cifs_buf_release(pSMB);
4111
4112 if (rc == -EAGAIN)
4113 goto setCifsAclRetry;
4114
4115 return (rc);
4116}
4117
Steve French0a4b92c2006-01-12 15:44:21 -08004118
Steve French6b8edfe2005-08-23 20:26:03 -07004119/* Legacy Query Path Information call for lookup to old servers such
4120 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004121int
4122SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4123 const char *search_name, FILE_ALL_INFO *data,
4124 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004125{
Steve Frenchad7a2922008-02-07 23:25:02 +00004126 QUERY_INFORMATION_REQ *pSMB;
4127 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004128 int rc = 0;
4129 int bytes_returned;
4130 int name_len;
4131
Joe Perchesf96637b2013-05-04 22:12:25 -05004132 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004133QInfRetry:
4134 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004135 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004136 if (rc)
4137 return rc;
4138
4139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4140 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004141 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004142 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004143 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004144 name_len++; /* trailing null */
4145 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004146 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004147 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004148 }
4149 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004150 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004151 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004152 pSMB->ByteCount = cpu_to_le16(name_len);
4153
4154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004155 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004156 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004157 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004158 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004159 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004160 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004161
4162 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004163 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004164 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004165 ts.tv_nsec = 0;
4166 ts.tv_sec = time;
4167 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004168 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4169 data->LastWriteTime = data->ChangeTime;
4170 data->LastAccessTime = 0;
4171 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004172 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004173 data->EndOfFile = data->AllocationSize;
4174 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004175 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004176 } else
4177 rc = -EIO; /* bad buffer passed in */
4178
4179 cifs_buf_release(pSMB);
4180
4181 if (rc == -EAGAIN)
4182 goto QInfRetry;
4183
4184 return rc;
4185}
4186
Jeff Laytonbcd53572010-02-12 07:44:16 -05004187int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004188CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004189 u16 netfid, FILE_ALL_INFO *pFindData)
4190{
4191 struct smb_t2_qfi_req *pSMB = NULL;
4192 struct smb_t2_qfi_rsp *pSMBr = NULL;
4193 int rc = 0;
4194 int bytes_returned;
4195 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004196
Jeff Laytonbcd53572010-02-12 07:44:16 -05004197QFileInfoRetry:
4198 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4199 (void **) &pSMBr);
4200 if (rc)
4201 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004202
Jeff Laytonbcd53572010-02-12 07:44:16 -05004203 params = 2 /* level */ + 2 /* fid */;
4204 pSMB->t2.TotalDataCount = 0;
4205 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4206 /* BB find exact max data count below from sess structure BB */
4207 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4208 pSMB->t2.MaxSetupCount = 0;
4209 pSMB->t2.Reserved = 0;
4210 pSMB->t2.Flags = 0;
4211 pSMB->t2.Timeout = 0;
4212 pSMB->t2.Reserved2 = 0;
4213 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4214 Fid) - 4);
4215 pSMB->t2.DataCount = 0;
4216 pSMB->t2.DataOffset = 0;
4217 pSMB->t2.SetupCount = 1;
4218 pSMB->t2.Reserved3 = 0;
4219 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4220 byte_count = params + 1 /* pad */ ;
4221 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4222 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4223 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4224 pSMB->Pad = 0;
4225 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004226 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004227 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004228
4229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4231 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004232 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004233 } else { /* decode response */
4234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4235
4236 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4237 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004238 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004239 rc = -EIO; /* bad smb */
4240 else if (pFindData) {
4241 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4242 memcpy((char *) pFindData,
4243 (char *) &pSMBr->hdr.Protocol +
4244 data_offset, sizeof(FILE_ALL_INFO));
4245 } else
4246 rc = -ENOMEM;
4247 }
4248 cifs_buf_release(pSMB);
4249 if (rc == -EAGAIN)
4250 goto QFileInfoRetry;
4251
4252 return rc;
4253}
Steve French6b8edfe2005-08-23 20:26:03 -07004254
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004256CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004257 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004258 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004259 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004261 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 TRANSACTION2_QPI_REQ *pSMB = NULL;
4263 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4264 int rc = 0;
4265 int bytes_returned;
4266 int name_len;
4267 __u16 params, byte_count;
4268
Joe Perchesf96637b2013-05-04 22:12:25 -05004269 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270QPathInfoRetry:
4271 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4272 (void **) &pSMBr);
4273 if (rc)
4274 return rc;
4275
4276 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4277 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004278 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004279 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 name_len++; /* trailing null */
4281 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004282 } else {
4283 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 }
4285
Steve French50c2f752007-07-13 00:33:32 +00004286 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 pSMB->TotalDataCount = 0;
4288 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004289 /* BB find exact max SMB PDU from sess structure BB */
4290 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 pSMB->MaxSetupCount = 0;
4292 pSMB->Reserved = 0;
4293 pSMB->Flags = 0;
4294 pSMB->Timeout = 0;
4295 pSMB->Reserved2 = 0;
4296 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004297 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 pSMB->DataCount = 0;
4299 pSMB->DataOffset = 0;
4300 pSMB->SetupCount = 1;
4301 pSMB->Reserved3 = 0;
4302 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4303 byte_count = params + 1 /* pad */ ;
4304 pSMB->TotalParameterCount = cpu_to_le16(params);
4305 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004306 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004307 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4308 else
4309 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004311 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 pSMB->ByteCount = cpu_to_le16(byte_count);
4313
4314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4315 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4316 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004317 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 } else { /* decode response */
4319 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4320
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004321 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4322 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004323 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004325 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004326 rc = -EIO; /* 24 or 26 expected but we do not read
4327 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004328 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004329 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004331
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004332 /*
4333 * On legacy responses we do not read the last field,
4334 * EAsize, fortunately since it varies by subdialect and
4335 * also note it differs on Set vs Get, ie two bytes or 4
4336 * bytes depending but we don't care here.
4337 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004338 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004339 size = sizeof(FILE_INFO_STANDARD);
4340 else
4341 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004342 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004343 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 } else
4345 rc = -ENOMEM;
4346 }
4347 cifs_buf_release(pSMB);
4348 if (rc == -EAGAIN)
4349 goto QPathInfoRetry;
4350
4351 return rc;
4352}
4353
4354int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004355CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004356 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4357{
4358 struct smb_t2_qfi_req *pSMB = NULL;
4359 struct smb_t2_qfi_rsp *pSMBr = NULL;
4360 int rc = 0;
4361 int bytes_returned;
4362 __u16 params, byte_count;
4363
4364UnixQFileInfoRetry:
4365 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4366 (void **) &pSMBr);
4367 if (rc)
4368 return rc;
4369
4370 params = 2 /* level */ + 2 /* fid */;
4371 pSMB->t2.TotalDataCount = 0;
4372 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4373 /* BB find exact max data count below from sess structure BB */
4374 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4375 pSMB->t2.MaxSetupCount = 0;
4376 pSMB->t2.Reserved = 0;
4377 pSMB->t2.Flags = 0;
4378 pSMB->t2.Timeout = 0;
4379 pSMB->t2.Reserved2 = 0;
4380 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4381 Fid) - 4);
4382 pSMB->t2.DataCount = 0;
4383 pSMB->t2.DataOffset = 0;
4384 pSMB->t2.SetupCount = 1;
4385 pSMB->t2.Reserved3 = 0;
4386 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4387 byte_count = params + 1 /* pad */ ;
4388 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4389 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4390 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4391 pSMB->Pad = 0;
4392 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004393 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004394 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004395
4396 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4397 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4398 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004399 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004400 } else { /* decode response */
4401 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4402
Jeff Layton820a8032011-05-04 08:05:26 -04004403 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004404 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 -05004405 rc = -EIO; /* bad smb */
4406 } else {
4407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4408 memcpy((char *) pFindData,
4409 (char *) &pSMBr->hdr.Protocol +
4410 data_offset,
4411 sizeof(FILE_UNIX_BASIC_INFO));
4412 }
4413 }
4414
4415 cifs_buf_release(pSMB);
4416 if (rc == -EAGAIN)
4417 goto UnixQFileInfoRetry;
4418
4419 return rc;
4420}
4421
4422int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004423CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004425 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004426 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427{
4428/* SMB_QUERY_FILE_UNIX_BASIC */
4429 TRANSACTION2_QPI_REQ *pSMB = NULL;
4430 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4431 int rc = 0;
4432 int bytes_returned = 0;
4433 int name_len;
4434 __u16 params, byte_count;
4435
Joe Perchesf96637b2013-05-04 22:12:25 -05004436 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437UnixQPathInfoRetry:
4438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4439 (void **) &pSMBr);
4440 if (rc)
4441 return rc;
4442
4443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4444 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004445 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4446 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 name_len++; /* trailing null */
4448 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004449 } else {
4450 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 }
4452
Steve French50c2f752007-07-13 00:33:32 +00004453 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 pSMB->TotalDataCount = 0;
4455 pSMB->MaxParameterCount = cpu_to_le16(2);
4456 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004457 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 pSMB->MaxSetupCount = 0;
4459 pSMB->Reserved = 0;
4460 pSMB->Flags = 0;
4461 pSMB->Timeout = 0;
4462 pSMB->Reserved2 = 0;
4463 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004464 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 pSMB->DataCount = 0;
4466 pSMB->DataOffset = 0;
4467 pSMB->SetupCount = 1;
4468 pSMB->Reserved3 = 0;
4469 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4470 byte_count = params + 1 /* pad */ ;
4471 pSMB->TotalParameterCount = cpu_to_le16(params);
4472 pSMB->ParameterCount = pSMB->TotalParameterCount;
4473 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4474 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004475 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 pSMB->ByteCount = cpu_to_le16(byte_count);
4477
4478 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4479 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4480 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004481 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 } else { /* decode response */
4483 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4484
Jeff Layton820a8032011-05-04 08:05:26 -04004485 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004486 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 -07004487 rc = -EIO; /* bad smb */
4488 } else {
4489 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4490 memcpy((char *) pFindData,
4491 (char *) &pSMBr->hdr.Protocol +
4492 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004493 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 }
4495 }
4496 cifs_buf_release(pSMB);
4497 if (rc == -EAGAIN)
4498 goto UnixQPathInfoRetry;
4499
4500 return rc;
4501}
4502
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503/* xid, tcon, searchName and codepage are input parms, rest are returned */
4504int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004505CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004506 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004507 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004508 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509{
4510/* level 257 SMB_ */
4511 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4512 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004513 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 int rc = 0;
4515 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004516 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004518 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
Joe Perchesf96637b2013-05-04 22:12:25 -05004520 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521
4522findFirstRetry:
4523 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4524 (void **) &pSMBr);
4525 if (rc)
4526 return rc;
4527
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004528 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004529 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004530
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4532 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004533 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4534 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004535 /* We can not add the asterik earlier in case
4536 it got remapped to 0xF03A as if it were part of the
4537 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004539 if (msearch) {
4540 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4541 pSMB->FileName[name_len+1] = 0;
4542 pSMB->FileName[name_len+2] = '*';
4543 pSMB->FileName[name_len+3] = 0;
4544 name_len += 4; /* now the trailing null */
4545 /* null terminate just in case */
4546 pSMB->FileName[name_len] = 0;
4547 pSMB->FileName[name_len+1] = 0;
4548 name_len += 2;
4549 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004550 } else {
4551 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004552 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004553 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4554 name_len = PATH_MAX-2;
4555 /* overwrite nul byte */
4556 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4557 pSMB->FileName[name_len] = '*';
4558 pSMB->FileName[name_len+1] = 0;
4559 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 }
4562
4563 params = 12 + name_len /* includes null */ ;
4564 pSMB->TotalDataCount = 0; /* no EAs */
4565 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004566 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 pSMB->MaxSetupCount = 0;
4568 pSMB->Reserved = 0;
4569 pSMB->Flags = 0;
4570 pSMB->Timeout = 0;
4571 pSMB->Reserved2 = 0;
4572 byte_count = params + 1 /* pad */ ;
4573 pSMB->TotalParameterCount = cpu_to_le16(params);
4574 pSMB->ParameterCount = pSMB->TotalParameterCount;
4575 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004576 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4577 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 pSMB->DataCount = 0;
4579 pSMB->DataOffset = 0;
4580 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4581 pSMB->Reserved3 = 0;
4582 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4583 pSMB->SearchAttributes =
4584 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4585 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004586 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004587 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4589
4590 /* BB what should we set StorageType to? Does it matter? BB */
4591 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004592 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 pSMB->ByteCount = cpu_to_le16(byte_count);
4594
4595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004597 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598
Steve French88274812006-03-09 22:21:45 +00004599 if (rc) {/* BB add logic to retry regular search if Unix search
4600 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004602 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004603
Steve French88274812006-03-09 22:21:45 +00004604 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605
4606 /* BB eventually could optimize out free and realloc of buf */
4607 /* for this case */
4608 if (rc == -EAGAIN)
4609 goto findFirstRetry;
4610 } else { /* decode response */
4611 /* BB remember to free buffer if error BB */
4612 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004613 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004614 unsigned int lnoff;
4615
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004617 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 else
Steve French4b18f2a2008-04-29 00:06:05 +00004619 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
4621 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004622 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004623 psrch_inf->srch_entries_start =
4624 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4627 le16_to_cpu(pSMBr->t2.ParameterOffset));
4628
Steve French790fe572007-07-07 19:25:05 +00004629 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004630 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 else
Steve French4b18f2a2008-04-29 00:06:05 +00004632 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633
Steve French50c2f752007-07-13 00:33:32 +00004634 psrch_inf->entries_in_buffer =
4635 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004636 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004638 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004639 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004640 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004641 psrch_inf->last_entry = NULL;
4642 return rc;
4643 }
4644
Steve French0752f152008-10-07 20:03:33 +00004645 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004646 lnoff;
4647
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004648 if (pnetfid)
4649 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 } else {
4651 cifs_buf_release(pSMB);
4652 }
4653 }
4654
4655 return rc;
4656}
4657
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004658int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4659 __u16 searchHandle, __u16 search_flags,
4660 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661{
4662 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4663 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004664 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 char *response_data;
4666 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004667 int bytes_returned;
4668 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 __u16 params, byte_count;
4670
Joe Perchesf96637b2013-05-04 22:12:25 -05004671 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672
Steve French4b18f2a2008-04-29 00:06:05 +00004673 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 return -ENOENT;
4675
4676 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4677 (void **) &pSMBr);
4678 if (rc)
4679 return rc;
4680
Steve French50c2f752007-07-13 00:33:32 +00004681 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 byte_count = 0;
4683 pSMB->TotalDataCount = 0; /* no EAs */
4684 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004685 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 pSMB->MaxSetupCount = 0;
4687 pSMB->Reserved = 0;
4688 pSMB->Flags = 0;
4689 pSMB->Timeout = 0;
4690 pSMB->Reserved2 = 0;
4691 pSMB->ParameterOffset = cpu_to_le16(
4692 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4693 pSMB->DataCount = 0;
4694 pSMB->DataOffset = 0;
4695 pSMB->SetupCount = 1;
4696 pSMB->Reserved3 = 0;
4697 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4698 pSMB->SearchHandle = searchHandle; /* always kept as le */
4699 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004700 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4702 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004703 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704
4705 name_len = psrch_inf->resume_name_len;
4706 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004707 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4709 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004710 /* 14 byte parm len above enough for 2 byte null terminator */
4711 pSMB->ResumeFileName[name_len] = 0;
4712 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 } else {
4714 rc = -EINVAL;
4715 goto FNext2_err_exit;
4716 }
4717 byte_count = params + 1 /* pad */ ;
4718 pSMB->TotalParameterCount = cpu_to_le16(params);
4719 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004720 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004722
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004725 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 if (rc) {
4727 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004728 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004729 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004730 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004732 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 } else { /* decode response */
4734 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004735
Steve French790fe572007-07-07 19:25:05 +00004736 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004737 unsigned int lnoff;
4738
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 /* BB fixme add lock for file (srch_info) struct here */
4740 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004741 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 else
Steve French4b18f2a2008-04-29 00:06:05 +00004743 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 response_data = (char *) &pSMBr->hdr.Protocol +
4745 le16_to_cpu(pSMBr->t2.ParameterOffset);
4746 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4747 response_data = (char *)&pSMBr->hdr.Protocol +
4748 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004749 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004750 cifs_small_buf_release(
4751 psrch_inf->ntwrk_buf_start);
4752 else
4753 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 psrch_inf->srch_entries_start = response_data;
4755 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004756 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004757 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004758 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 else
Steve French4b18f2a2008-04-29 00:06:05 +00004760 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004761 psrch_inf->entries_in_buffer =
4762 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 psrch_inf->index_of_last_entry +=
4764 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004765 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004766 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004767 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004768 psrch_inf->last_entry = NULL;
4769 return rc;
4770 } else
4771 psrch_inf->last_entry =
4772 psrch_inf->srch_entries_start + lnoff;
4773
Joe Perchesf96637b2013-05-04 22:12:25 -05004774/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4775 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776
4777 /* BB fixme add unlock here */
4778 }
4779
4780 }
4781
4782 /* BB On error, should we leave previous search buf (and count and
4783 last entry fields) intact or free the previous one? */
4784
4785 /* Note: On -EAGAIN error only caller can retry on handle based calls
4786 since file handle passed in no longer valid */
4787FNext2_err_exit:
4788 if (rc != 0)
4789 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 return rc;
4791}
4792
4793int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004794CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004795 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796{
4797 int rc = 0;
4798 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799
Joe Perchesf96637b2013-05-04 22:12:25 -05004800 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4802
4803 /* no sense returning error if session restarted
4804 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004805 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 return 0;
4807 if (rc)
4808 return rc;
4809
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 pSMB->FileID = searchHandle;
4811 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004812 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004813 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004814 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004815 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004816
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004817 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818
4819 /* Since session is dead, search handle closed on server already */
4820 if (rc == -EAGAIN)
4821 rc = 0;
4822
4823 return rc;
4824}
4825
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004827CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004828 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004829 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830{
4831 int rc = 0;
4832 TRANSACTION2_QPI_REQ *pSMB = NULL;
4833 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4834 int name_len, bytes_returned;
4835 __u16 params, byte_count;
4836
Joe Perchesf96637b2013-05-04 22:12:25 -05004837 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004838 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004839 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
4841GetInodeNumberRetry:
4842 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004843 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 if (rc)
4845 return rc;
4846
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4848 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004849 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004850 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004851 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 name_len++; /* trailing null */
4853 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004854 } else {
4855 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 }
4857
4858 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4859 pSMB->TotalDataCount = 0;
4860 pSMB->MaxParameterCount = cpu_to_le16(2);
4861 /* BB find exact max data count below from sess structure BB */
4862 pSMB->MaxDataCount = cpu_to_le16(4000);
4863 pSMB->MaxSetupCount = 0;
4864 pSMB->Reserved = 0;
4865 pSMB->Flags = 0;
4866 pSMB->Timeout = 0;
4867 pSMB->Reserved2 = 0;
4868 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004869 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 pSMB->DataCount = 0;
4871 pSMB->DataOffset = 0;
4872 pSMB->SetupCount = 1;
4873 pSMB->Reserved3 = 0;
4874 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4875 byte_count = params + 1 /* pad */ ;
4876 pSMB->TotalParameterCount = cpu_to_le16(params);
4877 pSMB->ParameterCount = pSMB->TotalParameterCount;
4878 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4879 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004880 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 pSMB->ByteCount = cpu_to_le16(byte_count);
4882
4883 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4884 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4885 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004886 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 } else {
4888 /* decode response */
4889 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004891 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 /* If rc should we check for EOPNOSUPP and
4893 disable the srvino flag? or in caller? */
4894 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004895 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4897 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004898 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004900 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004901 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 rc = -EIO;
4903 goto GetInodeNumOut;
4904 }
4905 pfinfo = (struct file_internal_info *)
4906 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004907 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 }
4909 }
4910GetInodeNumOut:
4911 cifs_buf_release(pSMB);
4912 if (rc == -EAGAIN)
4913 goto GetInodeNumberRetry;
4914 return rc;
4915}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
4917int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004918CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004919 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004920 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004921 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922{
4923/* TRANS2_GET_DFS_REFERRAL */
4924 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4925 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 int rc = 0;
4927 int bytes_returned;
4928 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004930 *num_of_nodes = 0;
4931 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932
Joe Perchesf96637b2013-05-04 22:12:25 -05004933 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004934 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004936
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004938 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 (void **) &pSMBr);
4940 if (rc)
4941 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004942
4943 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004944 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004945 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004946 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004948 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004950 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
4953 if (ses->capabilities & CAP_UNICODE) {
4954 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4955 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004956 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004957 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004958 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 name_len++; /* trailing null */
4960 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004961 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004962 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 }
4964
Dan Carpenter65c3b202015-04-30 17:30:24 +03004965 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004966 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004967
Steve French50c2f752007-07-13 00:33:32 +00004968 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004969
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970 params = 2 /* level */ + name_len /*includes null */ ;
4971 pSMB->TotalDataCount = 0;
4972 pSMB->DataCount = 0;
4973 pSMB->DataOffset = 0;
4974 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004975 /* BB find exact max SMB PDU from sess structure BB */
4976 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 pSMB->MaxSetupCount = 0;
4978 pSMB->Reserved = 0;
4979 pSMB->Flags = 0;
4980 pSMB->Timeout = 0;
4981 pSMB->Reserved2 = 0;
4982 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004983 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 pSMB->SetupCount = 1;
4985 pSMB->Reserved3 = 0;
4986 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4987 byte_count = params + 3 /* pad */ ;
4988 pSMB->ParameterCount = cpu_to_le16(params);
4989 pSMB->TotalParameterCount = pSMB->ParameterCount;
4990 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004991 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 pSMB->ByteCount = cpu_to_le16(byte_count);
4993
4994 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4996 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004997 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004998 goto GetDFSRefExit;
4999 }
5000 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005002 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04005003 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005004 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04005005 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 }
Igor Mammedovfec45852008-05-16 13:06:30 +04005007
Joe Perchesf96637b2013-05-04 22:12:25 -05005008 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
5009 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04005010
5011 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01005012 rc = parse_dfs_referrals(&pSMBr->dfs_data,
5013 le16_to_cpu(pSMBr->t2.DataCount),
5014 num_of_nodes, target_nodes, nls_codepage,
5015 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06005016 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04005017
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00005019 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020
5021 if (rc == -EAGAIN)
5022 goto getDFSRetry;
5023
5024 return rc;
5025}
5026
Steve French20962432005-09-21 22:05:57 -07005027/* Query File System Info such as free space to old servers such as Win 9x */
5028int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005029SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5030 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005031{
5032/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5033 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5034 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5035 FILE_SYSTEM_ALLOC_INFO *response_data;
5036 int rc = 0;
5037 int bytes_returned = 0;
5038 __u16 params, byte_count;
5039
Joe Perchesf96637b2013-05-04 22:12:25 -05005040 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005041oldQFSInfoRetry:
5042 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5043 (void **) &pSMBr);
5044 if (rc)
5045 return rc;
Steve French20962432005-09-21 22:05:57 -07005046
5047 params = 2; /* level */
5048 pSMB->TotalDataCount = 0;
5049 pSMB->MaxParameterCount = cpu_to_le16(2);
5050 pSMB->MaxDataCount = cpu_to_le16(1000);
5051 pSMB->MaxSetupCount = 0;
5052 pSMB->Reserved = 0;
5053 pSMB->Flags = 0;
5054 pSMB->Timeout = 0;
5055 pSMB->Reserved2 = 0;
5056 byte_count = params + 1 /* pad */ ;
5057 pSMB->TotalParameterCount = cpu_to_le16(params);
5058 pSMB->ParameterCount = pSMB->TotalParameterCount;
5059 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5060 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5061 pSMB->DataCount = 0;
5062 pSMB->DataOffset = 0;
5063 pSMB->SetupCount = 1;
5064 pSMB->Reserved3 = 0;
5065 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5066 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005067 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005068 pSMB->ByteCount = cpu_to_le16(byte_count);
5069
5070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5072 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005073 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005074 } else { /* decode response */
5075 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5076
Jeff Layton820a8032011-05-04 08:05:26 -04005077 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005078 rc = -EIO; /* bad smb */
5079 else {
5080 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005081 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005082 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005083
Steve French50c2f752007-07-13 00:33:32 +00005084 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005085 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5086 FSData->f_bsize =
5087 le16_to_cpu(response_data->BytesPerSector) *
5088 le32_to_cpu(response_data->
5089 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005090 /*
5091 * much prefer larger but if server doesn't report
5092 * a valid size than 4K is a reasonable minimum
5093 */
5094 if (FSData->f_bsize < 512)
5095 FSData->f_bsize = 4096;
5096
Steve French20962432005-09-21 22:05:57 -07005097 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005098 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005099 FSData->f_bfree = FSData->f_bavail =
5100 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005101 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5102 (unsigned long long)FSData->f_blocks,
5103 (unsigned long long)FSData->f_bfree,
5104 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005105 }
5106 }
5107 cifs_buf_release(pSMB);
5108
5109 if (rc == -EAGAIN)
5110 goto oldQFSInfoRetry;
5111
5112 return rc;
5113}
5114
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005116CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5117 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118{
5119/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5120 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5121 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5122 FILE_SYSTEM_INFO *response_data;
5123 int rc = 0;
5124 int bytes_returned = 0;
5125 __u16 params, byte_count;
5126
Joe Perchesf96637b2013-05-04 22:12:25 -05005127 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128QFSInfoRetry:
5129 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5130 (void **) &pSMBr);
5131 if (rc)
5132 return rc;
5133
5134 params = 2; /* level */
5135 pSMB->TotalDataCount = 0;
5136 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005137 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 pSMB->MaxSetupCount = 0;
5139 pSMB->Reserved = 0;
5140 pSMB->Flags = 0;
5141 pSMB->Timeout = 0;
5142 pSMB->Reserved2 = 0;
5143 byte_count = params + 1 /* pad */ ;
5144 pSMB->TotalParameterCount = cpu_to_le16(params);
5145 pSMB->ParameterCount = pSMB->TotalParameterCount;
5146 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005147 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 pSMB->DataCount = 0;
5149 pSMB->DataOffset = 0;
5150 pSMB->SetupCount = 1;
5151 pSMB->Reserved3 = 0;
5152 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5153 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005154 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 pSMB->ByteCount = cpu_to_le16(byte_count);
5156
5157 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5158 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5159 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005160 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005162 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163
Jeff Layton820a8032011-05-04 08:05:26 -04005164 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 rc = -EIO; /* bad smb */
5166 else {
5167 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168
5169 response_data =
5170 (FILE_SYSTEM_INFO
5171 *) (((char *) &pSMBr->hdr.Protocol) +
5172 data_offset);
5173 FSData->f_bsize =
5174 le32_to_cpu(response_data->BytesPerSector) *
5175 le32_to_cpu(response_data->
5176 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005177 /*
5178 * much prefer larger but if server doesn't report
5179 * a valid size than 4K is a reasonable minimum
5180 */
5181 if (FSData->f_bsize < 512)
5182 FSData->f_bsize = 4096;
5183
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 FSData->f_blocks =
5185 le64_to_cpu(response_data->TotalAllocationUnits);
5186 FSData->f_bfree = FSData->f_bavail =
5187 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005188 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5189 (unsigned long long)FSData->f_blocks,
5190 (unsigned long long)FSData->f_bfree,
5191 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 }
5193 }
5194 cifs_buf_release(pSMB);
5195
5196 if (rc == -EAGAIN)
5197 goto QFSInfoRetry;
5198
5199 return rc;
5200}
5201
5202int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005203CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204{
5205/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5206 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5207 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5208 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5209 int rc = 0;
5210 int bytes_returned = 0;
5211 __u16 params, byte_count;
5212
Joe Perchesf96637b2013-05-04 22:12:25 -05005213 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214QFSAttributeRetry:
5215 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5216 (void **) &pSMBr);
5217 if (rc)
5218 return rc;
5219
5220 params = 2; /* level */
5221 pSMB->TotalDataCount = 0;
5222 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005223 /* BB find exact max SMB PDU from sess structure BB */
5224 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 pSMB->MaxSetupCount = 0;
5226 pSMB->Reserved = 0;
5227 pSMB->Flags = 0;
5228 pSMB->Timeout = 0;
5229 pSMB->Reserved2 = 0;
5230 byte_count = params + 1 /* pad */ ;
5231 pSMB->TotalParameterCount = cpu_to_le16(params);
5232 pSMB->ParameterCount = pSMB->TotalParameterCount;
5233 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005234 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 pSMB->DataCount = 0;
5236 pSMB->DataOffset = 0;
5237 pSMB->SetupCount = 1;
5238 pSMB->Reserved3 = 0;
5239 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5240 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005241 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 pSMB->ByteCount = cpu_to_le16(byte_count);
5243
5244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5246 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005247 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 } else { /* decode response */
5249 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5250
Jeff Layton820a8032011-05-04 08:05:26 -04005251 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005252 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 rc = -EIO; /* bad smb */
5254 } else {
5255 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5256 response_data =
5257 (FILE_SYSTEM_ATTRIBUTE_INFO
5258 *) (((char *) &pSMBr->hdr.Protocol) +
5259 data_offset);
5260 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005261 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 }
5263 }
5264 cifs_buf_release(pSMB);
5265
5266 if (rc == -EAGAIN)
5267 goto QFSAttributeRetry;
5268
5269 return rc;
5270}
5271
5272int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005273CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274{
5275/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5276 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5277 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5278 FILE_SYSTEM_DEVICE_INFO *response_data;
5279 int rc = 0;
5280 int bytes_returned = 0;
5281 __u16 params, byte_count;
5282
Joe Perchesf96637b2013-05-04 22:12:25 -05005283 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284QFSDeviceRetry:
5285 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5286 (void **) &pSMBr);
5287 if (rc)
5288 return rc;
5289
5290 params = 2; /* level */
5291 pSMB->TotalDataCount = 0;
5292 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005293 /* BB find exact max SMB PDU from sess structure BB */
5294 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 pSMB->MaxSetupCount = 0;
5296 pSMB->Reserved = 0;
5297 pSMB->Flags = 0;
5298 pSMB->Timeout = 0;
5299 pSMB->Reserved2 = 0;
5300 byte_count = params + 1 /* pad */ ;
5301 pSMB->TotalParameterCount = cpu_to_le16(params);
5302 pSMB->ParameterCount = pSMB->TotalParameterCount;
5303 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005304 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
5306 pSMB->DataCount = 0;
5307 pSMB->DataOffset = 0;
5308 pSMB->SetupCount = 1;
5309 pSMB->Reserved3 = 0;
5310 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5311 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005312 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 pSMB->ByteCount = cpu_to_le16(byte_count);
5314
5315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5317 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005318 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 } else { /* decode response */
5320 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5321
Jeff Layton820a8032011-05-04 08:05:26 -04005322 if (rc || get_bcc(&pSMBr->hdr) <
5323 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 rc = -EIO; /* bad smb */
5325 else {
5326 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5327 response_data =
Steve French737b7582005-04-28 22:41:06 -07005328 (FILE_SYSTEM_DEVICE_INFO *)
5329 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 data_offset);
5331 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005332 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 }
5334 }
5335 cifs_buf_release(pSMB);
5336
5337 if (rc == -EAGAIN)
5338 goto QFSDeviceRetry;
5339
5340 return rc;
5341}
5342
5343int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005344CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345{
5346/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5347 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5348 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5349 FILE_SYSTEM_UNIX_INFO *response_data;
5350 int rc = 0;
5351 int bytes_returned = 0;
5352 __u16 params, byte_count;
5353
Joe Perchesf96637b2013-05-04 22:12:25 -05005354 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005356 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5357 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 if (rc)
5359 return rc;
5360
5361 params = 2; /* level */
5362 pSMB->TotalDataCount = 0;
5363 pSMB->DataCount = 0;
5364 pSMB->DataOffset = 0;
5365 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005366 /* BB find exact max SMB PDU from sess structure BB */
5367 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 pSMB->MaxSetupCount = 0;
5369 pSMB->Reserved = 0;
5370 pSMB->Flags = 0;
5371 pSMB->Timeout = 0;
5372 pSMB->Reserved2 = 0;
5373 byte_count = params + 1 /* pad */ ;
5374 pSMB->ParameterCount = cpu_to_le16(params);
5375 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005376 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5377 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 pSMB->SetupCount = 1;
5379 pSMB->Reserved3 = 0;
5380 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5381 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005382 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 pSMB->ByteCount = cpu_to_le16(byte_count);
5384
5385 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5386 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5387 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005388 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 } else { /* decode response */
5390 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5391
Jeff Layton820a8032011-05-04 08:05:26 -04005392 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 rc = -EIO; /* bad smb */
5394 } else {
5395 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5396 response_data =
5397 (FILE_SYSTEM_UNIX_INFO
5398 *) (((char *) &pSMBr->hdr.Protocol) +
5399 data_offset);
5400 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005401 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 }
5403 }
5404 cifs_buf_release(pSMB);
5405
5406 if (rc == -EAGAIN)
5407 goto QFSUnixRetry;
5408
5409
5410 return rc;
5411}
5412
Jeremy Allisonac670552005-06-22 17:26:35 -07005413int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005414CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005415{
5416/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5417 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5418 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5419 int rc = 0;
5420 int bytes_returned = 0;
5421 __u16 params, param_offset, offset, byte_count;
5422
Joe Perchesf96637b2013-05-04 22:12:25 -05005423 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005424SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005425 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005426 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5427 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005428 if (rc)
5429 return rc;
5430
5431 params = 4; /* 2 bytes zero followed by info level. */
5432 pSMB->MaxSetupCount = 0;
5433 pSMB->Reserved = 0;
5434 pSMB->Flags = 0;
5435 pSMB->Timeout = 0;
5436 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005437 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5438 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005439 offset = param_offset + params;
5440
5441 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005442 /* BB find exact max SMB PDU from sess structure BB */
5443 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005444 pSMB->SetupCount = 1;
5445 pSMB->Reserved3 = 0;
5446 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5447 byte_count = 1 /* pad */ + params + 12;
5448
5449 pSMB->DataCount = cpu_to_le16(12);
5450 pSMB->ParameterCount = cpu_to_le16(params);
5451 pSMB->TotalDataCount = pSMB->DataCount;
5452 pSMB->TotalParameterCount = pSMB->ParameterCount;
5453 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5454 pSMB->DataOffset = cpu_to_le16(offset);
5455
5456 /* Params. */
5457 pSMB->FileNum = 0;
5458 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5459
5460 /* Data. */
5461 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5462 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5463 pSMB->ClientUnixCap = cpu_to_le64(cap);
5464
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005465 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005466 pSMB->ByteCount = cpu_to_le16(byte_count);
5467
5468 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5469 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5470 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005471 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005472 } else { /* decode response */
5473 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005474 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005475 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005476 }
5477 cifs_buf_release(pSMB);
5478
5479 if (rc == -EAGAIN)
5480 goto SETFSUnixRetry;
5481
5482 return rc;
5483}
5484
5485
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486
5487int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005488CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005489 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490{
5491/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5492 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5493 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5494 FILE_SYSTEM_POSIX_INFO *response_data;
5495 int rc = 0;
5496 int bytes_returned = 0;
5497 __u16 params, byte_count;
5498
Joe Perchesf96637b2013-05-04 22:12:25 -05005499 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500QFSPosixRetry:
5501 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5502 (void **) &pSMBr);
5503 if (rc)
5504 return rc;
5505
5506 params = 2; /* level */
5507 pSMB->TotalDataCount = 0;
5508 pSMB->DataCount = 0;
5509 pSMB->DataOffset = 0;
5510 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005511 /* BB find exact max SMB PDU from sess structure BB */
5512 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 pSMB->MaxSetupCount = 0;
5514 pSMB->Reserved = 0;
5515 pSMB->Flags = 0;
5516 pSMB->Timeout = 0;
5517 pSMB->Reserved2 = 0;
5518 byte_count = params + 1 /* pad */ ;
5519 pSMB->ParameterCount = cpu_to_le16(params);
5520 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005521 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5522 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 pSMB->SetupCount = 1;
5524 pSMB->Reserved3 = 0;
5525 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5526 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005527 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 pSMB->ByteCount = cpu_to_le16(byte_count);
5529
5530 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5531 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5532 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005533 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 } else { /* decode response */
5535 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5536
Jeff Layton820a8032011-05-04 08:05:26 -04005537 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 rc = -EIO; /* bad smb */
5539 } else {
5540 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5541 response_data =
5542 (FILE_SYSTEM_POSIX_INFO
5543 *) (((char *) &pSMBr->hdr.Protocol) +
5544 data_offset);
5545 FSData->f_bsize =
5546 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005547 /*
5548 * much prefer larger but if server doesn't report
5549 * a valid size than 4K is a reasonable minimum
5550 */
5551 if (FSData->f_bsize < 512)
5552 FSData->f_bsize = 4096;
5553
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 FSData->f_blocks =
5555 le64_to_cpu(response_data->TotalBlocks);
5556 FSData->f_bfree =
5557 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005558 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 FSData->f_bavail = FSData->f_bfree;
5560 } else {
5561 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005562 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 }
Steve French790fe572007-07-07 19:25:05 +00005564 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005566 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005567 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005569 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 }
5571 }
5572 cifs_buf_release(pSMB);
5573
5574 if (rc == -EAGAIN)
5575 goto QFSPosixRetry;
5576
5577 return rc;
5578}
5579
5580
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005581/*
5582 * We can not use write of zero bytes trick to set file size due to need for
5583 * large file support. Also note that this SetPathInfo is preferred to
5584 * SetFileInfo based method in next routine which is only needed to work around
5585 * a sharing violation bugin Samba which this routine can run into.
5586 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005588CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005589 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5590 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591{
5592 struct smb_com_transaction2_spi_req *pSMB = NULL;
5593 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5594 struct file_end_of_file_info *parm_data;
5595 int name_len;
5596 int rc = 0;
5597 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005598 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005599
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 __u16 params, byte_count, data_count, param_offset, offset;
5601
Joe Perchesf96637b2013-05-04 22:12:25 -05005602 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603SetEOFRetry:
5604 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5605 (void **) &pSMBr);
5606 if (rc)
5607 return rc;
5608
5609 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5610 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005611 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5612 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 name_len++; /* trailing null */
5614 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005615 } else {
5616 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 }
5618 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005619 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005621 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 pSMB->MaxSetupCount = 0;
5623 pSMB->Reserved = 0;
5624 pSMB->Flags = 0;
5625 pSMB->Timeout = 0;
5626 pSMB->Reserved2 = 0;
5627 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005628 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005630 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005631 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5632 pSMB->InformationLevel =
5633 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5634 else
5635 pSMB->InformationLevel =
5636 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5637 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5639 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005640 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 else
5642 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005643 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 }
5645
5646 parm_data =
5647 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5648 offset);
5649 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5650 pSMB->DataOffset = cpu_to_le16(offset);
5651 pSMB->SetupCount = 1;
5652 pSMB->Reserved3 = 0;
5653 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5654 byte_count = 3 /* pad */ + params + data_count;
5655 pSMB->DataCount = cpu_to_le16(data_count);
5656 pSMB->TotalDataCount = pSMB->DataCount;
5657 pSMB->ParameterCount = cpu_to_le16(params);
5658 pSMB->TotalParameterCount = pSMB->ParameterCount;
5659 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005660 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 parm_data->FileSize = cpu_to_le64(size);
5662 pSMB->ByteCount = cpu_to_le16(byte_count);
5663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005665 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005666 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
5668 cifs_buf_release(pSMB);
5669
5670 if (rc == -EAGAIN)
5671 goto SetEOFRetry;
5672
5673 return rc;
5674}
5675
5676int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005677CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5678 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679{
5680 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 struct file_end_of_file_info *parm_data;
5682 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 __u16 params, param_offset, offset, byte_count, count;
5684
Joe Perchesf96637b2013-05-04 22:12:25 -05005685 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5686 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005687 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5688
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 if (rc)
5690 return rc;
5691
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005692 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5693 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005694
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 params = 6;
5696 pSMB->MaxSetupCount = 0;
5697 pSMB->Reserved = 0;
5698 pSMB->Flags = 0;
5699 pSMB->Timeout = 0;
5700 pSMB->Reserved2 = 0;
5701 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5702 offset = param_offset + params;
5703
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 count = sizeof(struct file_end_of_file_info);
5705 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005706 /* BB find exact max SMB PDU from sess structure BB */
5707 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708 pSMB->SetupCount = 1;
5709 pSMB->Reserved3 = 0;
5710 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5711 byte_count = 3 /* pad */ + params + count;
5712 pSMB->DataCount = cpu_to_le16(count);
5713 pSMB->ParameterCount = cpu_to_le16(params);
5714 pSMB->TotalDataCount = pSMB->DataCount;
5715 pSMB->TotalParameterCount = pSMB->ParameterCount;
5716 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5717 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005718 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5719 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 pSMB->DataOffset = cpu_to_le16(offset);
5721 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005722 pSMB->Fid = cfile->fid.netfid;
5723 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5725 pSMB->InformationLevel =
5726 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5727 else
5728 pSMB->InformationLevel =
5729 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005730 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5732 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005733 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 else
5735 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005736 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 }
5738 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005739 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005741 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005742 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005744 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5745 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 }
5747
Steve French50c2f752007-07-13 00:33:32 +00005748 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 since file handle passed in no longer valid */
5750
5751 return rc;
5752}
5753
Steve French50c2f752007-07-13 00:33:32 +00005754/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 an open handle, rather than by pathname - this is awkward due to
5756 potential access conflicts on the open, but it is unavoidable for these
5757 old servers since the only other choice is to go from 100 nanosecond DCE
5758 time and resort to the original setpathinfo level which takes the ancient
5759 DOS time format with 2 second granularity */
5760int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005761CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005762 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763{
5764 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 char *data_offset;
5766 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 __u16 params, param_offset, offset, byte_count, count;
5768
Joe Perchesf96637b2013-05-04 22:12:25 -05005769 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005770 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5771
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772 if (rc)
5773 return rc;
5774
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005775 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5776 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005777
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 params = 6;
5779 pSMB->MaxSetupCount = 0;
5780 pSMB->Reserved = 0;
5781 pSMB->Flags = 0;
5782 pSMB->Timeout = 0;
5783 pSMB->Reserved2 = 0;
5784 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5785 offset = param_offset + params;
5786
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005787 data_offset = (char *)pSMB +
5788 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
Steve French26f57362007-08-30 22:09:15 +00005790 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005792 /* BB find max SMB PDU from sess */
5793 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 pSMB->SetupCount = 1;
5795 pSMB->Reserved3 = 0;
5796 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5797 byte_count = 3 /* pad */ + params + count;
5798 pSMB->DataCount = cpu_to_le16(count);
5799 pSMB->ParameterCount = cpu_to_le16(params);
5800 pSMB->TotalDataCount = pSMB->DataCount;
5801 pSMB->TotalParameterCount = pSMB->ParameterCount;
5802 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5803 pSMB->DataOffset = cpu_to_le16(offset);
5804 pSMB->Fid = fid;
5805 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5806 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5807 else
5808 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5809 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005810 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005812 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005813 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005814 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005815 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005816 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5817 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818
Steve French50c2f752007-07-13 00:33:32 +00005819 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 since file handle passed in no longer valid */
5821
5822 return rc;
5823}
5824
Jeff Layton6d22f092008-09-23 11:48:35 -04005825int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005826CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005827 bool delete_file, __u16 fid, __u32 pid_of_opener)
5828{
5829 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5830 char *data_offset;
5831 int rc = 0;
5832 __u16 params, param_offset, offset, byte_count, count;
5833
Joe Perchesf96637b2013-05-04 22:12:25 -05005834 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005835 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5836
5837 if (rc)
5838 return rc;
5839
5840 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5841 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5842
5843 params = 6;
5844 pSMB->MaxSetupCount = 0;
5845 pSMB->Reserved = 0;
5846 pSMB->Flags = 0;
5847 pSMB->Timeout = 0;
5848 pSMB->Reserved2 = 0;
5849 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5850 offset = param_offset + params;
5851
5852 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5853
5854 count = 1;
5855 pSMB->MaxParameterCount = cpu_to_le16(2);
5856 /* BB find max SMB PDU from sess */
5857 pSMB->MaxDataCount = cpu_to_le16(1000);
5858 pSMB->SetupCount = 1;
5859 pSMB->Reserved3 = 0;
5860 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5861 byte_count = 3 /* pad */ + params + count;
5862 pSMB->DataCount = cpu_to_le16(count);
5863 pSMB->ParameterCount = cpu_to_le16(params);
5864 pSMB->TotalDataCount = pSMB->DataCount;
5865 pSMB->TotalParameterCount = pSMB->ParameterCount;
5866 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5867 pSMB->DataOffset = cpu_to_le16(offset);
5868 pSMB->Fid = fid;
5869 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5870 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005871 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005872 pSMB->ByteCount = cpu_to_le16(byte_count);
5873 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005874 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005875 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005876 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005877 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005878
5879 return rc;
5880}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881
5882int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005883CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005884 const char *fileName, const FILE_BASIC_INFO *data,
5885 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886{
5887 TRANSACTION2_SPI_REQ *pSMB = NULL;
5888 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5889 int name_len;
5890 int rc = 0;
5891 int bytes_returned = 0;
5892 char *data_offset;
5893 __u16 params, param_offset, offset, byte_count, count;
5894
Joe Perchesf96637b2013-05-04 22:12:25 -05005895 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896
5897SetTimesRetry:
5898 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5899 (void **) &pSMBr);
5900 if (rc)
5901 return rc;
5902
5903 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5904 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005905 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5906 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 name_len++; /* trailing null */
5908 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005909 } else {
5910 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 }
5912
5913 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005914 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005916 /* BB find max SMB PDU from sess structure BB */
5917 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918 pSMB->MaxSetupCount = 0;
5919 pSMB->Reserved = 0;
5920 pSMB->Flags = 0;
5921 pSMB->Timeout = 0;
5922 pSMB->Reserved2 = 0;
5923 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005924 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 offset = param_offset + params;
5926 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5927 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5928 pSMB->DataOffset = cpu_to_le16(offset);
5929 pSMB->SetupCount = 1;
5930 pSMB->Reserved3 = 0;
5931 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5932 byte_count = 3 /* pad */ + params + count;
5933
5934 pSMB->DataCount = cpu_to_le16(count);
5935 pSMB->ParameterCount = cpu_to_le16(params);
5936 pSMB->TotalDataCount = pSMB->DataCount;
5937 pSMB->TotalParameterCount = pSMB->ParameterCount;
5938 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5939 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5940 else
5941 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5942 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005943 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005944 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945 pSMB->ByteCount = cpu_to_le16(byte_count);
5946 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005948 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005949 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950
5951 cifs_buf_release(pSMB);
5952
5953 if (rc == -EAGAIN)
5954 goto SetTimesRetry;
5955
5956 return rc;
5957}
5958
5959/* Can not be used to set time stamps yet (due to old DOS time format) */
5960/* Can be used to set attributes */
5961#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5962 handling it anyway and NT4 was what we thought it would be needed for
5963 Do not delete it until we prove whether needed for Win9x though */
5964int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005965CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 __u16 dos_attrs, const struct nls_table *nls_codepage)
5967{
5968 SETATTR_REQ *pSMB = NULL;
5969 SETATTR_RSP *pSMBr = NULL;
5970 int rc = 0;
5971 int bytes_returned;
5972 int name_len;
5973
Joe Perchesf96637b2013-05-04 22:12:25 -05005974 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975
5976SetAttrLgcyRetry:
5977 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5978 (void **) &pSMBr);
5979 if (rc)
5980 return rc;
5981
5982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5983 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005984 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5985 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986 name_len++; /* trailing null */
5987 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005988 } else {
5989 name_len = copy_path_name(pSMB->fileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 }
5991 pSMB->attr = cpu_to_le16(dos_attrs);
5992 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005993 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005997 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005998 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999
6000 cifs_buf_release(pSMB);
6001
6002 if (rc == -EAGAIN)
6003 goto SetAttrLgcyRetry;
6004
6005 return rc;
6006}
6007#endif /* temporarily unneeded SetAttr legacy function */
6008
Jeff Layton654cf142009-07-09 20:02:49 -04006009static void
6010cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
6011 const struct cifs_unix_set_info_args *args)
6012{
Eric W. Biederman49418b22013-02-06 00:57:56 -08006013 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04006014 u64 mode = args->mode;
6015
Eric W. Biederman49418b22013-02-06 00:57:56 -08006016 if (uid_valid(args->uid))
6017 uid = from_kuid(&init_user_ns, args->uid);
6018 if (gid_valid(args->gid))
6019 gid = from_kgid(&init_user_ns, args->gid);
6020
Jeff Layton654cf142009-07-09 20:02:49 -04006021 /*
6022 * Samba server ignores set of file size to zero due to bugs in some
6023 * older clients, but we should be precise - we use SetFileSize to
6024 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006025 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04006026 * zero instead of -1 here
6027 */
6028 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
6029 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
6030 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
6031 data_offset->LastAccessTime = cpu_to_le64(args->atime);
6032 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08006033 data_offset->Uid = cpu_to_le64(uid);
6034 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04006035 /* better to leave device as zero when it is */
6036 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
6037 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
6038 data_offset->Permissions = cpu_to_le64(mode);
6039
6040 if (S_ISREG(mode))
6041 data_offset->Type = cpu_to_le32(UNIX_FILE);
6042 else if (S_ISDIR(mode))
6043 data_offset->Type = cpu_to_le32(UNIX_DIR);
6044 else if (S_ISLNK(mode))
6045 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6046 else if (S_ISCHR(mode))
6047 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6048 else if (S_ISBLK(mode))
6049 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6050 else if (S_ISFIFO(mode))
6051 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6052 else if (S_ISSOCK(mode))
6053 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6054}
6055
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006057CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006058 const struct cifs_unix_set_info_args *args,
6059 u16 fid, u32 pid_of_opener)
6060{
6061 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006062 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006063 int rc = 0;
6064 u16 params, param_offset, offset, byte_count, count;
6065
Joe Perchesf96637b2013-05-04 22:12:25 -05006066 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006067 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6068
6069 if (rc)
6070 return rc;
6071
6072 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6073 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6074
6075 params = 6;
6076 pSMB->MaxSetupCount = 0;
6077 pSMB->Reserved = 0;
6078 pSMB->Flags = 0;
6079 pSMB->Timeout = 0;
6080 pSMB->Reserved2 = 0;
6081 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6082 offset = param_offset + params;
6083
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006084 data_offset = (char *)pSMB +
6085 offsetof(struct smb_hdr, Protocol) + offset;
6086
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006087 count = sizeof(FILE_UNIX_BASIC_INFO);
6088
6089 pSMB->MaxParameterCount = cpu_to_le16(2);
6090 /* BB find max SMB PDU from sess */
6091 pSMB->MaxDataCount = cpu_to_le16(1000);
6092 pSMB->SetupCount = 1;
6093 pSMB->Reserved3 = 0;
6094 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6095 byte_count = 3 /* pad */ + params + count;
6096 pSMB->DataCount = cpu_to_le16(count);
6097 pSMB->ParameterCount = cpu_to_le16(params);
6098 pSMB->TotalDataCount = pSMB->DataCount;
6099 pSMB->TotalParameterCount = pSMB->ParameterCount;
6100 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6101 pSMB->DataOffset = cpu_to_le16(offset);
6102 pSMB->Fid = fid;
6103 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6104 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006105 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006106 pSMB->ByteCount = cpu_to_le16(byte_count);
6107
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006108 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006109
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006110 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006111 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006112 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006113 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6114 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006115
6116 /* Note: On -EAGAIN error only caller can retry on handle based calls
6117 since file handle passed in no longer valid */
6118
6119 return rc;
6120}
6121
6122int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006123CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006124 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006125 const struct cifs_unix_set_info_args *args,
6126 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127{
6128 TRANSACTION2_SPI_REQ *pSMB = NULL;
6129 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6130 int name_len;
6131 int rc = 0;
6132 int bytes_returned = 0;
6133 FILE_UNIX_BASIC_INFO *data_offset;
6134 __u16 params, param_offset, offset, count, byte_count;
6135
Joe Perchesf96637b2013-05-04 22:12:25 -05006136 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137setPermsRetry:
6138 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6139 (void **) &pSMBr);
6140 if (rc)
6141 return rc;
6142
6143 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6144 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006145 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006146 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 name_len++; /* trailing null */
6148 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006149 } else {
6150 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 }
6152
6153 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006154 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006156 /* BB find max SMB PDU from sess structure BB */
6157 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 pSMB->MaxSetupCount = 0;
6159 pSMB->Reserved = 0;
6160 pSMB->Flags = 0;
6161 pSMB->Timeout = 0;
6162 pSMB->Reserved2 = 0;
6163 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006164 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 offset = param_offset + params;
6166 data_offset =
6167 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6168 offset);
6169 memset(data_offset, 0, count);
6170 pSMB->DataOffset = cpu_to_le16(offset);
6171 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6172 pSMB->SetupCount = 1;
6173 pSMB->Reserved3 = 0;
6174 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6175 byte_count = 3 /* pad */ + params + count;
6176 pSMB->ParameterCount = cpu_to_le16(params);
6177 pSMB->DataCount = cpu_to_le16(count);
6178 pSMB->TotalParameterCount = pSMB->ParameterCount;
6179 pSMB->TotalDataCount = pSMB->DataCount;
6180 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6181 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006182 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006183
Jeff Layton654cf142009-07-09 20:02:49 -04006184 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185
6186 pSMB->ByteCount = cpu_to_le16(byte_count);
6187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006189 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006190 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191
Steve French0d817bc2008-05-22 02:02:03 +00006192 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193 if (rc == -EAGAIN)
6194 goto setPermsRetry;
6195 return rc;
6196}
6197
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006199/*
6200 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6201 * function used by listxattr and getxattr type calls. When ea_name is set,
6202 * it looks for that attribute name and stuffs that value into the EAData
6203 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6204 * buffer. In both cases, the return value is either the length of the
6205 * resulting data or a negative error code. If EAData is a NULL pointer then
6206 * the data isn't copied to it, but the length is returned.
6207 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006209CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006210 const unsigned char *searchName, const unsigned char *ea_name,
6211 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006212 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213{
6214 /* BB assumes one setup word */
6215 TRANSACTION2_QPI_REQ *pSMB = NULL;
6216 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006217 int remap = cifs_remap(cifs_sb);
6218 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 int rc = 0;
6220 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006221 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006222 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006223 struct fea *temp_fea;
6224 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006225 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006226 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006227 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
Joe Perchesf96637b2013-05-04 22:12:25 -05006229 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230QAllEAsRetry:
6231 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6232 (void **) &pSMBr);
6233 if (rc)
6234 return rc;
6235
6236 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006237 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006238 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6239 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006240 list_len++; /* trailing null */
6241 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006242 } else {
6243 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 }
6245
Jeff Layton6e462b92010-02-10 16:18:26 -05006246 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247 pSMB->TotalDataCount = 0;
6248 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006249 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006250 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 pSMB->MaxSetupCount = 0;
6252 pSMB->Reserved = 0;
6253 pSMB->Flags = 0;
6254 pSMB->Timeout = 0;
6255 pSMB->Reserved2 = 0;
6256 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006257 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258 pSMB->DataCount = 0;
6259 pSMB->DataOffset = 0;
6260 pSMB->SetupCount = 1;
6261 pSMB->Reserved3 = 0;
6262 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6263 byte_count = params + 1 /* pad */ ;
6264 pSMB->TotalParameterCount = cpu_to_le16(params);
6265 pSMB->ParameterCount = pSMB->TotalParameterCount;
6266 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6267 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006268 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 pSMB->ByteCount = cpu_to_le16(byte_count);
6270
6271 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6272 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6273 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006274 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006275 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006277
6278
6279 /* BB also check enough total bytes returned */
6280 /* BB we need to improve the validity checking
6281 of these trans2 responses */
6282
6283 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006284 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006285 rc = -EIO; /* bad smb */
6286 goto QAllEAsOut;
6287 }
6288
6289 /* check that length of list is not more than bcc */
6290 /* check that each entry does not go beyond length
6291 of list */
6292 /* check that each element of each entry does not
6293 go beyond end of list */
6294 /* validate_trans2_offsets() */
6295 /* BB check if start of smb + data_offset > &bcc+ bcc */
6296
6297 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6298 ea_response_data = (struct fealist *)
6299 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6300
Jeff Layton6e462b92010-02-10 16:18:26 -05006301 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006302 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006303 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006304 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006305 /* didn't find the named attribute */
6306 if (ea_name)
6307 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006308 goto QAllEAsOut;
6309 }
6310
Jeff Layton0cd126b2010-02-10 16:18:26 -05006311 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006312 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006313 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006314 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006315 rc = -EIO;
6316 goto QAllEAsOut;
6317 }
6318
Jeff Laytonf0d38682010-02-10 16:18:26 -05006319 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006320 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006321 temp_fea = ea_response_data->list;
6322 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006323 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006324 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006325 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006326
Jeff Layton6e462b92010-02-10 16:18:26 -05006327 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006328 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006329 /* make sure we can read name_len and value_len */
6330 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006331 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006332 rc = -EIO;
6333 goto QAllEAsOut;
6334 }
6335
6336 name_len = temp_fea->name_len;
6337 value_len = le16_to_cpu(temp_fea->value_len);
6338 list_len -= name_len + 1 + value_len;
6339 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006340 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006341 rc = -EIO;
6342 goto QAllEAsOut;
6343 }
6344
Jeff Layton31c05192010-02-10 16:18:26 -05006345 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006346 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006347 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006348 temp_ptr += name_len + 1;
6349 rc = value_len;
6350 if (buf_size == 0)
6351 goto QAllEAsOut;
6352 if ((size_t)value_len > buf_size) {
6353 rc = -ERANGE;
6354 goto QAllEAsOut;
6355 }
6356 memcpy(EAData, temp_ptr, value_len);
6357 goto QAllEAsOut;
6358 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006359 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006360 /* account for prefix user. and trailing null */
6361 rc += (5 + 1 + name_len);
6362 if (rc < (int) buf_size) {
6363 memcpy(EAData, "user.", 5);
6364 EAData += 5;
6365 memcpy(EAData, temp_ptr, name_len);
6366 EAData += name_len;
6367 /* null terminate name */
6368 *EAData = 0;
6369 ++EAData;
6370 } else if (buf_size == 0) {
6371 /* skip copy - calc size only */
6372 } else {
6373 /* stop before overrun buffer */
6374 rc = -ERANGE;
6375 break;
6376 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006377 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006378 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006379 temp_fea = (struct fea *)temp_ptr;
6380 }
6381
Jeff Layton31c05192010-02-10 16:18:26 -05006382 /* didn't find the named attribute */
6383 if (ea_name)
6384 rc = -ENODATA;
6385
Jeff Laytonf0d38682010-02-10 16:18:26 -05006386QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006387 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 if (rc == -EAGAIN)
6389 goto QAllEAsRetry;
6390
6391 return (ssize_t)rc;
6392}
6393
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006395CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6396 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006397 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006398 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399{
6400 struct smb_com_transaction2_spi_req *pSMB = NULL;
6401 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6402 struct fealist *parm_data;
6403 int name_len;
6404 int rc = 0;
6405 int bytes_returned = 0;
6406 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006407 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408
Joe Perchesf96637b2013-05-04 22:12:25 -05006409 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410SetEARetry:
6411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6412 (void **) &pSMBr);
6413 if (rc)
6414 return rc;
6415
6416 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6417 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006418 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6419 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420 name_len++; /* trailing null */
6421 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006422 } else {
6423 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424 }
6425
6426 params = 6 + name_len;
6427
6428 /* done calculating parms using name_len of file name,
6429 now use name_len to calculate length of ea name
6430 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006431 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006432 name_len = 0;
6433 else
Steve French50c2f752007-07-13 00:33:32 +00006434 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006435
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006436 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006438 /* BB find max SMB PDU from sess */
6439 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 pSMB->MaxSetupCount = 0;
6441 pSMB->Reserved = 0;
6442 pSMB->Flags = 0;
6443 pSMB->Timeout = 0;
6444 pSMB->Reserved2 = 0;
6445 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006446 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447 offset = param_offset + params;
6448 pSMB->InformationLevel =
6449 cpu_to_le16(SMB_SET_FILE_EA);
6450
Arnd Bergmannade7db92018-02-02 16:48:47 +01006451 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6453 pSMB->DataOffset = cpu_to_le16(offset);
6454 pSMB->SetupCount = 1;
6455 pSMB->Reserved3 = 0;
6456 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6457 byte_count = 3 /* pad */ + params + count;
6458 pSMB->DataCount = cpu_to_le16(count);
6459 parm_data->list_len = cpu_to_le32(count);
6460 parm_data->list[0].EA_flags = 0;
6461 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006462 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006464 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006465 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466 parm_data->list[0].name[name_len] = 0;
6467 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6468 /* caller ensures that ea_value_len is less than 64K but
6469 we need to ensure that it fits within the smb */
6470
Steve French50c2f752007-07-13 00:33:32 +00006471 /*BB add length check to see if it would fit in
6472 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006473 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6474 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006475 memcpy(parm_data->list[0].name+name_len+1,
6476 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477
6478 pSMB->TotalDataCount = pSMB->DataCount;
6479 pSMB->ParameterCount = cpu_to_le16(params);
6480 pSMB->TotalParameterCount = pSMB->ParameterCount;
6481 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006482 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483 pSMB->ByteCount = cpu_to_le16(byte_count);
6484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006486 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006487 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006488
6489 cifs_buf_release(pSMB);
6490
6491 if (rc == -EAGAIN)
6492 goto SetEARetry;
6493
6494 return rc;
6495}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496#endif