blob: d4f94406a808e63a310dfc6a070798bb7238fa5f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080038#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070046#include "smbdirect.h"
Paulo Alcantara08744012018-11-14 17:24:29 -020047#ifdef CONFIG_CIFS_DFS_UPCALL
48#include "dfs_cache.h"
49#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#ifdef CONFIG_CIFS_POSIX
52static struct {
53 int index;
54 char *name;
55} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000056#ifdef CONFIG_CIFS_WEAK_PW_HASH
57 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000058 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000059#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000060 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000061 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 {BAD_PROT, "\2"}
63};
64#else
65static struct {
66 int index;
67 char *name;
68} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000069#ifdef CONFIG_CIFS_WEAK_PW_HASH
70 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000071 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000072#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000073 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 {BAD_PROT, "\2"}
75};
76#endif
77
Steve French39798772006-05-31 22:40:51 +000078/* define the number of elements in the cifs dialect array */
79#ifdef CONFIG_CIFS_POSIX
80#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000081#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000082#else
83#define CIFS_NUM_PROT 2
84#endif /* CIFS_WEAK_PW_HASH */
85#else /* not posix */
86#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000087#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000088#else
89#define CIFS_NUM_PROT 1
90#endif /* CONFIG_CIFS_WEAK_PW_HASH */
91#endif /* CIFS_POSIX */
92
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040093/*
94 * Mark as invalid, all open files on tree connections since they
95 * were closed when session to server was lost.
96 */
97void
98cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
100 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000101 struct list_head *tmp;
102 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400104 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500105 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400106 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000107 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000108 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400109 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 }
Steve French3afca262016-09-22 18:58:16 -0500111 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -0500112
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000113 mutex_lock(&tcon->crfid.fid_mutex);
114 tcon->crfid.is_valid = false;
115 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
116 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -0500117
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400118 /*
119 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
120 * to this tcon.
121 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
Paulo Alcantara08744012018-11-14 17:24:29 -0200124#ifdef CONFIG_CIFS_DFS_UPCALL
125static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
126 struct cifs_tcon *tcon)
127{
128 int rc;
129 struct dfs_cache_tgt_list tl;
130 struct dfs_cache_tgt_iterator *it = NULL;
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100131 char *tree;
Paulo Alcantara08744012018-11-14 17:24:29 -0200132 const char *tcp_host;
133 size_t tcp_host_len;
134 const char *dfs_host;
135 size_t dfs_host_len;
136
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100137 tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
138 if (!tree)
139 return -ENOMEM;
140
Paulo Alcantara08744012018-11-14 17:24:29 -0200141 if (tcon->ipc) {
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +1000142 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
143 tcon->ses->server->hostname);
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100144 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
145 goto out;
Paulo Alcantara08744012018-11-14 17:24:29 -0200146 }
147
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100148 if (!tcon->dfs_path) {
149 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
150 goto out;
151 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200152
153 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
154 if (rc)
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100155 goto out;
Paulo Alcantara08744012018-11-14 17:24:29 -0200156
157 extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
158 &tcp_host_len);
159
160 for (it = dfs_cache_get_tgt_iterator(&tl); it;
161 it = dfs_cache_get_next_tgt(&tl, it)) {
162 const char *tgt = dfs_cache_get_tgt_name(it);
163
164 extract_unc_hostname(tgt, &dfs_host, &dfs_host_len);
165
166 if (dfs_host_len != tcp_host_len
167 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
168 cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
169 __func__,
170 (int)dfs_host_len, dfs_host,
171 (int)tcp_host_len, tcp_host);
172 continue;
173 }
174
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +1000175 scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt);
Paulo Alcantara08744012018-11-14 17:24:29 -0200176
177 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
178 if (!rc)
179 break;
180 if (rc == -EREMOTE)
181 break;
182 }
183
184 if (!rc) {
185 if (it)
186 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
187 it);
188 else
189 rc = -ENOENT;
190 }
191 dfs_cache_free_tgts(&tl);
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100192out:
193 kfree(tree);
Paulo Alcantara08744012018-11-14 17:24:29 -0200194 return rc;
195}
196#else
197static inline int __cifs_reconnect_tcon(const struct nls_table *nlsc,
198 struct cifs_tcon *tcon)
199{
200 return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
201}
202#endif
203
Jeff Layton9162ab22009-09-03 12:07:17 -0400204/* reconnect the socket, tcon, and smb session if needed */
205static int
Steve French96daf2b2011-05-27 04:34:02 +0000206cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400207{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400208 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000209 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400210 struct TCP_Server_Info *server;
211 struct nls_table *nls_codepage;
Paulo Alcantara08744012018-11-14 17:24:29 -0200212 int retries;
Jeff Layton9162ab22009-09-03 12:07:17 -0400213
214 /*
215 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
216 * tcp and smb session status done differently for those three - in the
217 * calling routine
218 */
219 if (!tcon)
220 return 0;
221
222 ses = tcon->ses;
223 server = ses->server;
224
225 /*
226 * only tree disconnect, open, and write, (and ulogoff which does not
227 * have tcon) are allowed as we start force umount
228 */
229 if (tcon->tidStatus == CifsExiting) {
230 if (smb_command != SMB_COM_WRITE_ANDX &&
231 smb_command != SMB_COM_OPEN_ANDX &&
232 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500233 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
234 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400235 return -ENODEV;
236 }
237 }
238
Paulo Alcantara08744012018-11-14 17:24:29 -0200239 retries = server->nr_targets;
240
Jeff Layton9162ab22009-09-03 12:07:17 -0400241 /*
Paulo Alcantara08744012018-11-14 17:24:29 -0200242 * Give demultiplex thread up to 10 seconds to each target available for
243 * reconnect -- should be greater than cifs socket timeout which is 7
244 * seconds.
Jeff Layton9162ab22009-09-03 12:07:17 -0400245 */
246 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300247 rc = wait_event_interruptible_timeout(server->response_q,
248 (server->tcpStatus != CifsNeedReconnect),
249 10 * HZ);
250 if (rc < 0) {
251 cifs_dbg(FYI, "%s: aborting reconnect due to a received"
252 " signal by the process\n", __func__);
253 return -ERESTARTSYS;
254 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400255
Steve Frenchfd88ce92011-04-12 01:01:14 +0000256 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400257 if (server->tcpStatus != CifsNeedReconnect)
258 break;
259
Paulo Alcantara08744012018-11-14 17:24:29 -0200260 if (--retries)
261 continue;
262
Jeff Layton9162ab22009-09-03 12:07:17 -0400263 /*
264 * on "soft" mounts we wait once. Hard mounts keep
265 * retrying until process is killed or server comes
266 * back on-line
267 */
Jeff Laytond4025392011-02-07 08:54:35 -0500268 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500269 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400270 return -EHOSTDOWN;
271 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200272 retries = server->nr_targets;
Jeff Layton9162ab22009-09-03 12:07:17 -0400273 }
274
275 if (!ses->need_reconnect && !tcon->need_reconnect)
276 return 0;
277
278 nls_codepage = load_nls_default();
279
280 /*
281 * need to prevent multiple threads trying to simultaneously
282 * reconnect the same SMB session
283 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000284 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200285
286 /*
287 * Recheck after acquire mutex. If another thread is negotiating
288 * and the server never sends an answer the socket will be closed
289 * and tcpStatus set to reconnect.
290 */
291 if (server->tcpStatus == CifsNeedReconnect) {
292 rc = -EHOSTDOWN;
293 mutex_unlock(&ses->session_mutex);
294 goto out;
295 }
296
Jeff Layton198b5682010-04-24 07:57:48 -0400297 rc = cifs_negotiate_protocol(0, ses);
298 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400299 rc = cifs_setup_session(0, ses, nls_codepage);
300
301 /* do we need to reconnect tcon? */
302 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000303 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400304 goto out;
305 }
306
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400307 cifs_mark_open_files_invalid(tcon);
Paulo Alcantara08744012018-11-14 17:24:29 -0200308 rc = __cifs_reconnect_tcon(nls_codepage, tcon);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000309 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500310 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400311
Steve Frenchc318e6c2018-04-04 14:08:52 -0500312 if (rc) {
313 printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400314 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500315 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400316
Jeff Layton9162ab22009-09-03 12:07:17 -0400317 atomic_inc(&tconInfoReconnectCount);
318
319 /* tell server Unix caps we support */
320 if (ses->capabilities & CAP_UNIX)
321 reset_cifs_unix_caps(0, tcon, NULL, NULL);
322
323 /*
324 * Removed call to reopen open files here. It is safer (and faster) to
325 * reopen files one at a time as needed in read and write.
326 *
327 * FIXME: what about file locks? don't we need to reclaim them ASAP?
328 */
329
330out:
331 /*
332 * Check if handle based operation so we know whether we can continue
333 * or not without returning to caller to reset file handle
334 */
335 switch (smb_command) {
336 case SMB_COM_READ_ANDX:
337 case SMB_COM_WRITE_ANDX:
338 case SMB_COM_CLOSE:
339 case SMB_COM_FIND_CLOSE2:
340 case SMB_COM_LOCKING_ANDX:
341 rc = -EAGAIN;
342 }
343
344 unload_nls(nls_codepage);
345 return rc;
346}
347
Steve Frenchad7a2922008-02-07 23:25:02 +0000348/* Allocate and return pointer to an SMB request buffer, and set basic
349 SMB information in the SMB header. If the return code is zero, this
350 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351static int
Steve French96daf2b2011-05-27 04:34:02 +0000352small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000353 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Jeff Laytonf5695992010-09-29 15:27:08 -0400355 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Jeff Layton9162ab22009-09-03 12:07:17 -0400357 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000358 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 return rc;
360
361 *request_buf = cifs_small_buf_get();
362 if (*request_buf == NULL) {
363 /* BB should we add a retry in here if not a writepage? */
364 return -ENOMEM;
365 }
366
Steve French63135e02007-07-17 17:34:02 +0000367 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000368 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Steve French790fe572007-07-07 19:25:05 +0000370 if (tcon != NULL)
371 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700372
Jeff Laytonf5695992010-09-29 15:27:08 -0400373 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000374}
375
Steve French12b3b8f2006-02-09 21:12:47 +0000376int
Steve French50c2f752007-07-13 00:33:32 +0000377small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000378 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000379{
380 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000381 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000382
Steve French5815449d2006-02-14 01:36:20 +0000383 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000384 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000385 return rc;
386
Steve French04fdabe2006-02-10 05:52:50 +0000387 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400388 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000389 if (ses->capabilities & CAP_UNICODE)
390 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000391 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000392 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
393
394 /* uid, tid can stay at zero as set in header assemble */
395
Steve French50c2f752007-07-13 00:33:32 +0000396 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000397 this function is used after 1st of session setup requests */
398
399 return rc;
400}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402/* If the return code is zero, this function must fill in request_buf pointer */
403static int
Steve French96daf2b2011-05-27 04:34:02 +0000404__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400405 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 *request_buf = cifs_buf_get();
408 if (*request_buf == NULL) {
409 /* BB should we add a retry in here if not a writepage? */
410 return -ENOMEM;
411 }
412 /* Although the original thought was we needed the response buf for */
413 /* potential retries of smb operations it turns out we can determine */
414 /* from the mid flags when the request buffer can be resent without */
415 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000416 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000417 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000420 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Steve French790fe572007-07-07 19:25:05 +0000422 if (tcon != NULL)
423 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700424
Jeff Laytonf5695992010-09-29 15:27:08 -0400425 return 0;
426}
427
428/* If the return code is zero, this function must fill in request_buf pointer */
429static int
Steve French96daf2b2011-05-27 04:34:02 +0000430smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400431 void **request_buf, void **response_buf)
432{
433 int rc;
434
435 rc = cifs_reconnect_tcon(tcon, smb_command);
436 if (rc)
437 return rc;
438
439 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
440}
441
442static int
Steve French96daf2b2011-05-27 04:34:02 +0000443smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400444 void **request_buf, void **response_buf)
445{
446 if (tcon->ses->need_reconnect || tcon->need_reconnect)
447 return -EHOSTDOWN;
448
449 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
451
Steve French50c2f752007-07-13 00:33:32 +0000452static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Jeff Layton12df83c2011-01-20 13:36:51 -0500454 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Jeff Layton12df83c2011-01-20 13:36:51 -0500456 /* check for plausible wct */
457 if (pSMB->hdr.WordCount < 10)
458 goto vt2_err;
459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500461 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
462 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
463 goto vt2_err;
464
Jeff Layton12df83c2011-01-20 13:36:51 -0500465 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
466 if (total_size >= 512)
467 goto vt2_err;
468
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400469 /* check that bcc is at least as big as parms + data, and that it is
470 * less than negotiated smb buffer
471 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500472 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
473 if (total_size > get_bcc(&pSMB->hdr) ||
474 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
475 goto vt2_err;
476
477 return 0;
478vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000479 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500481 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482}
Jeff Layton690c5222011-01-20 13:36:51 -0500483
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400484static int
Jeff Layton3f618222013-06-12 19:52:14 -0500485decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400486{
487 int rc = 0;
488 u16 count;
489 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500490 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400491
492 count = get_bcc(&pSMBr->hdr);
493 if (count < SMB1_CLIENT_GUID_SIZE)
494 return -EIO;
495
496 spin_lock(&cifs_tcp_ses_lock);
497 if (server->srv_count > 1) {
498 spin_unlock(&cifs_tcp_ses_lock);
499 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
500 cifs_dbg(FYI, "server UID changed\n");
501 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
502 }
503 } else {
504 spin_unlock(&cifs_tcp_ses_lock);
505 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
506 }
507
508 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500509 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400510 } else {
511 count -= SMB1_CLIENT_GUID_SIZE;
512 rc = decode_negTokenInit(
513 pSMBr->u.extended_response.SecurityBlob, count, server);
514 if (rc != 1)
515 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400516 }
517
518 return 0;
519}
520
Jeff Layton9ddec562013-05-26 07:00:58 -0400521int
Jeff Layton38d77c52013-05-26 07:01:00 -0400522cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400523{
Jeff Layton502858822013-06-27 12:45:00 -0400524 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
525 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400526 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
527
528 /*
529 * Is signing required by mnt options? If not then check
530 * global_secflags to see if it is there.
531 */
532 if (!mnt_sign_required)
533 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
534 CIFSSEC_MUST_SIGN);
535
536 /*
537 * If signing is required then it's automatically enabled too,
538 * otherwise, check to see if the secflags allow it.
539 */
540 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
541 (global_secflags & CIFSSEC_MAY_SIGN);
542
543 /* If server requires signing, does client allow it? */
544 if (srv_sign_required) {
545 if (!mnt_sign_enabled) {
546 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
547 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400548 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400549 server->sign = true;
550 }
551
552 /* If client requires signing, does server allow it? */
553 if (mnt_sign_required) {
554 if (!srv_sign_enabled) {
555 cifs_dbg(VFS, "Server does not support signing!");
556 return -ENOTSUPP;
557 }
558 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400559 }
560
Long Libb4c0412018-04-17 12:17:08 -0700561 if (cifs_rdma_enabled(server) && server->sign)
562 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled");
563
Jeff Layton9ddec562013-05-26 07:00:58 -0400564 return 0;
565}
566
Jeff Layton2190eca2013-05-26 07:00:57 -0400567#ifdef CONFIG_CIFS_WEAK_PW_HASH
568static int
Jeff Layton3f618222013-06-12 19:52:14 -0500569decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400570{
571 __s16 tmp;
572 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
573
574 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
575 return -EOPNOTSUPP;
576
Jeff Layton2190eca2013-05-26 07:00:57 -0400577 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
578 server->maxReq = min_t(unsigned int,
579 le16_to_cpu(rsp->MaxMpxCount),
580 cifs_max_pending);
581 set_credits(server, server->maxReq);
582 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400583 /* even though we do not use raw we might as well set this
584 accurately, in case we ever find a need for it */
585 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
586 server->max_rw = 0xFF00;
587 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
588 } else {
589 server->max_rw = 0;/* do not need to use raw anyway */
590 server->capabilities = CAP_MPX_MODE;
591 }
592 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
593 if (tmp == -1) {
594 /* OS/2 often does not set timezone therefore
595 * we must use server time to calc time zone.
596 * Could deviate slightly from the right zone.
597 * Smallest defined timezone difference is 15 minutes
598 * (i.e. Nepal). Rounding up/down is done to match
599 * this requirement.
600 */
601 int val, seconds, remain, result;
Arnd Bergmann95390202018-06-19 17:27:58 +0200602 struct timespec64 ts;
603 time64_t utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400604 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
605 rsp->SrvTime.Time, 0);
Arnd Bergmann95390202018-06-19 17:27:58 +0200606 cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
607 ts.tv_sec, utc,
608 utc - ts.tv_sec);
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700609 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400610 seconds = abs(val);
611 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
612 remain = seconds % MIN_TZ_ADJ;
613 if (remain >= (MIN_TZ_ADJ / 2))
614 result += MIN_TZ_ADJ;
615 if (val < 0)
616 result = -result;
617 server->timeAdj = result;
618 } else {
619 server->timeAdj = (int)tmp;
620 server->timeAdj *= 60; /* also in seconds */
621 }
622 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
623
624
625 /* BB get server time for time conversions and add
626 code to use it and timezone since this is not UTC */
627
628 if (rsp->EncryptionKeyLength ==
629 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
630 memcpy(server->cryptkey, rsp->EncryptionKey,
631 CIFS_CRYPTO_KEY_SIZE);
632 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
633 return -EIO; /* need cryptkey unless plain text */
634 }
635
636 cifs_dbg(FYI, "LANMAN negotiated\n");
637 return 0;
638}
639#else
640static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500641decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400642{
643 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
644 return -EOPNOTSUPP;
645}
646#endif
647
Jeff Layton91934002013-05-26 07:00:58 -0400648static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500649should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400650{
Jeff Layton3f618222013-06-12 19:52:14 -0500651 switch (sectype) {
652 case RawNTLMSSP:
653 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400654 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500655 case Unspecified:
656 if (global_secflags &
657 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
658 return true;
659 /* Fallthrough */
660 default:
661 return false;
662 }
Jeff Layton91934002013-05-26 07:00:58 -0400663}
664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400666CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 NEGOTIATE_REQ *pSMB;
669 NEGOTIATE_RSP *pSMBr;
670 int rc = 0;
671 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000672 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400673 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 u16 count;
675
Jeff Layton3534b852013-05-24 07:41:01 -0400676 if (!server) {
677 WARN(1, "%s: server is NULL!\n", __func__);
678 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
Jeff Layton3534b852013-05-24 07:41:01 -0400680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
682 (void **) &pSMB, (void **) &pSMBr);
683 if (rc)
684 return rc;
Steve French750d1152006-06-27 06:28:30 +0000685
Pavel Shilovsky88257362012-05-23 14:01:59 +0400686 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000687 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000688
Jeff Layton3f618222013-06-12 19:52:14 -0500689 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400690 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000691 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
692 }
Steve French50c2f752007-07-13 00:33:32 +0000693
Steve French39798772006-05-31 22:40:51 +0000694 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000695 /*
696 * We know that all the name entries in the protocols array
697 * are short (< 16 bytes anyway) and are NUL terminated.
698 */
Steve French50c2f752007-07-13 00:33:32 +0000699 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000700 size_t len = strlen(protocols[i].name) + 1;
701
702 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
703 count += len;
Steve French39798772006-05-31 22:40:51 +0000704 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000705 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 pSMB->ByteCount = cpu_to_le16(count);
707
708 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
709 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000710 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000711 goto neg_err_exit;
712
Jeff Layton9bf67e52010-04-24 07:57:46 -0400713 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500714 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000715 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400716 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000717 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000718 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000719 could not negotiate a common dialect */
720 rc = -EOPNOTSUPP;
721 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000722 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400723 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500724 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400725 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000726 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000727 /* unknown wct */
728 rc = -EOPNOTSUPP;
729 goto neg_err_exit;
730 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400731 /* else wct == 17, NTLM or better */
732
Steve French96daf2b2011-05-27 04:34:02 +0000733 server->sec_mode = pSMBr->SecurityMode;
734 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500735 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000736
Steve French254e55e2006-06-04 05:53:15 +0000737 /* one byte, so no need to convert this or EncryptionKeyLen from
738 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300739 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
740 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400741 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000742 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400743 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000744 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500745 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000746 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000747 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
748 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400749
Jeff Laytone598d1d82013-05-26 07:00:59 -0400750 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
751 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500752 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000753 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100754 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
755 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400756 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500757 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400758 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000759 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400760 } else {
761 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000762 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400763 }
Steve French254e55e2006-06-04 05:53:15 +0000764
765signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400766 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400767 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000768neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700769 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000770
Joe Perchesf96637b2013-05-04 22:12:25 -0500771 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return rc;
773}
774
775int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400776CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
778 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Joe Perchesf96637b2013-05-04 22:12:25 -0500781 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500782
783 /* BB: do we need to check this? These should never be NULL. */
784 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
785 return -EIO;
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500788 * No need to return error on this operation if tid invalidated and
789 * closed on server already e.g. due to tcp session crashing. Also,
790 * the tcon is no longer on the list, so no need to take lock before
791 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 */
Steve French268875b2009-06-25 00:29:21 +0000793 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000794 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Steve French50c2f752007-07-13 00:33:32 +0000796 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700797 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500798 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 return rc;
Steve French133672e2007-11-13 22:41:37 +0000800
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400801 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700802 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500804 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Steve French50c2f752007-07-13 00:33:32 +0000806 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500807 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 if (rc == -EAGAIN)
809 rc = 0;
810
811 return rc;
812}
813
Jeff Layton766fdbb2011-01-11 07:24:21 -0500814/*
815 * This is a no-op for now. We're not really interested in the reply, but
816 * rather in the fact that the server sent one and that server->lstrp
817 * gets updated.
818 *
819 * FIXME: maybe we should consider checking that the reply matches request?
820 */
821static void
822cifs_echo_callback(struct mid_q_entry *mid)
823{
824 struct TCP_Server_Info *server = mid->callback_data;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800825 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500826
827 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800828 add_credits(server, &credits, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500829}
830
831int
832CIFSSMBEcho(struct TCP_Server_Info *server)
833{
834 ECHO_REQ *smb;
835 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800836 struct kvec iov[2];
837 struct smb_rqst rqst = { .rq_iov = iov,
838 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500839
Joe Perchesf96637b2013-05-04 22:12:25 -0500840 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500841
842 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
843 if (rc)
844 return rc;
845
Steve French26c9cb62017-05-02 13:35:20 -0500846 if (server->capabilities & CAP_UNICODE)
847 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
848
Jeff Layton766fdbb2011-01-11 07:24:21 -0500849 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000850 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500851 smb->hdr.WordCount = 1;
852 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400853 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500854 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000855 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800856
857 iov[0].iov_len = 4;
858 iov[0].iov_base = smb;
859 iov[1].iov_len = get_rfc1002_length(smb);
860 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500861
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800862 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400863 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500864 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500865 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500866
867 cifs_small_buf_release(smb);
868
869 return rc;
870}
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400873CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 LOGOFF_ANDX_REQ *pSMB;
876 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Joe Perchesf96637b2013-05-04 22:12:25 -0500878 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500879
880 /*
881 * BB: do we need to check validity of ses and server? They should
882 * always be valid since we have an active reference. If not, that
883 * should probably be a BUG()
884 */
885 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return -EIO;
887
Steve Frenchd7b619c2010-02-25 05:36:46 +0000888 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000889 if (ses->need_reconnect)
890 goto session_already_dead; /* no need to send SMBlogoff if uid
891 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
893 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000894 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 return rc;
896 }
897
Pavel Shilovsky88257362012-05-23 14:01:59 +0400898 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700899
Jeff Layton38d77c52013-05-26 07:01:00 -0400900 if (ses->server->sign)
901 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903 pSMB->hdr.Uid = ses->Suid;
904
905 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400906 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700907 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000908session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000909 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000912 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 error */
914 if (rc == -EAGAIN)
915 rc = 0;
916 return rc;
917}
918
919int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400920CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
921 const char *fileName, __u16 type,
922 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000923{
924 TRANSACTION2_SPI_REQ *pSMB = NULL;
925 TRANSACTION2_SPI_RSP *pSMBr = NULL;
926 struct unlink_psx_rq *pRqD;
927 int name_len;
928 int rc = 0;
929 int bytes_returned = 0;
930 __u16 params, param_offset, offset, byte_count;
931
Joe Perchesf96637b2013-05-04 22:12:25 -0500932 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000933PsxDelete:
934 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
938
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600941 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
942 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000943 name_len++; /* trailing null */
944 name_len *= 2;
945 } else { /* BB add path length overrun check */
946 name_len = strnlen(fileName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->FileName, fileName, name_len);
949 }
950
951 params = 6 + name_len;
952 pSMB->MaxParameterCount = cpu_to_le16(2);
953 pSMB->MaxDataCount = 0; /* BB double check this with jra */
954 pSMB->MaxSetupCount = 0;
955 pSMB->Reserved = 0;
956 pSMB->Flags = 0;
957 pSMB->Timeout = 0;
958 pSMB->Reserved2 = 0;
959 param_offset = offsetof(struct smb_com_transaction2_spi_req,
960 InformationLevel) - 4;
961 offset = param_offset + params;
962
963 /* Setup pointer to Request Data (inode type) */
964 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
965 pRqD->type = cpu_to_le16(type);
966 pSMB->ParameterOffset = cpu_to_le16(param_offset);
967 pSMB->DataOffset = cpu_to_le16(offset);
968 pSMB->SetupCount = 1;
969 pSMB->Reserved3 = 0;
970 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
971 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
972
973 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
974 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
975 pSMB->ParameterCount = cpu_to_le16(params);
976 pSMB->TotalParameterCount = pSMB->ParameterCount;
977 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
978 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000979 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000980 pSMB->ByteCount = cpu_to_le16(byte_count);
981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000983 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500984 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000985 cifs_buf_release(pSMB);
986
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400987 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000988
989 if (rc == -EAGAIN)
990 goto PsxDelete;
991
992 return rc;
993}
994
995int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700996CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
997 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
999 DELETE_FILE_REQ *pSMB = NULL;
1000 DELETE_FILE_RSP *pSMBr = NULL;
1001 int rc = 0;
1002 int bytes_returned;
1003 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001004 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006DelFileRetry:
1007 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
1008 (void **) &pSMBr);
1009 if (rc)
1010 return rc;
1011
1012 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -07001013 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
1014 PATH_MAX, cifs_sb->local_nls,
1015 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 name_len++; /* trailing null */
1017 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001018 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -07001019 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -07001021 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
1023 pSMB->SearchAttributes =
1024 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
1025 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001026 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001030 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +00001031 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001032 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 cifs_buf_release(pSMB);
1035 if (rc == -EAGAIN)
1036 goto DelFileRetry;
1037
1038 return rc;
1039}
1040
1041int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001042CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1043 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044{
1045 DELETE_DIRECTORY_REQ *pSMB = NULL;
1046 DELETE_DIRECTORY_RSP *pSMBr = NULL;
1047 int rc = 0;
1048 int bytes_returned;
1049 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001050 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Joe Perchesf96637b2013-05-04 22:12:25 -05001052 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053RmDirRetry:
1054 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
1055 (void **) &pSMBr);
1056 if (rc)
1057 return rc;
1058
1059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001060 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1061 PATH_MAX, cifs_sb->local_nls,
1062 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 name_len++; /* trailing null */
1064 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001065 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001066 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001068 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 }
1070
1071 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001072 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001076 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001077 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001078 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 cifs_buf_release(pSMB);
1081 if (rc == -EAGAIN)
1082 goto RmDirRetry;
1083 return rc;
1084}
1085
1086int
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001087CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1088 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089{
1090 int rc = 0;
1091 CREATE_DIRECTORY_REQ *pSMB = NULL;
1092 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1093 int bytes_returned;
1094 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001095 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
Joe Perchesf96637b2013-05-04 22:12:25 -05001097 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098MkDirRetry:
1099 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1100 (void **) &pSMBr);
1101 if (rc)
1102 return rc;
1103
1104 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001105 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001106 PATH_MAX, cifs_sb->local_nls,
1107 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 name_len++; /* trailing null */
1109 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001110 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 name_len = strnlen(name, PATH_MAX);
1112 name_len++; /* trailing null */
1113 strncpy(pSMB->DirName, name, name_len);
1114 }
1115
1116 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001117 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001121 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001122 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001123 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 cifs_buf_release(pSMB);
1126 if (rc == -EAGAIN)
1127 goto MkDirRetry;
1128 return rc;
1129}
1130
Steve French2dd29d32007-04-23 22:07:35 +00001131int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001132CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1133 __u32 posix_flags, __u64 mode, __u16 *netfid,
1134 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1135 const char *name, const struct nls_table *nls_codepage,
1136 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001137{
1138 TRANSACTION2_SPI_REQ *pSMB = NULL;
1139 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1140 int name_len;
1141 int rc = 0;
1142 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001143 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001144 OPEN_PSX_REQ *pdata;
1145 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001146
Joe Perchesf96637b2013-05-04 22:12:25 -05001147 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001148PsxCreat:
1149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1150 (void **) &pSMBr);
1151 if (rc)
1152 return rc;
1153
1154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1155 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001156 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1157 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001158 name_len++; /* trailing null */
1159 name_len *= 2;
1160 } else { /* BB improve the check for buffer overruns BB */
1161 name_len = strnlen(name, PATH_MAX);
1162 name_len++; /* trailing null */
1163 strncpy(pSMB->FileName, name, name_len);
1164 }
1165
1166 params = 6 + name_len;
1167 count = sizeof(OPEN_PSX_REQ);
1168 pSMB->MaxParameterCount = cpu_to_le16(2);
1169 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1170 pSMB->MaxSetupCount = 0;
1171 pSMB->Reserved = 0;
1172 pSMB->Flags = 0;
1173 pSMB->Timeout = 0;
1174 pSMB->Reserved2 = 0;
1175 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001176 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001177 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001178 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001179 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001180 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001181 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001182 pdata->OpenFlags = cpu_to_le32(*pOplock);
1183 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1184 pSMB->DataOffset = cpu_to_le16(offset);
1185 pSMB->SetupCount = 1;
1186 pSMB->Reserved3 = 0;
1187 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1188 byte_count = 3 /* pad */ + params + count;
1189
1190 pSMB->DataCount = cpu_to_le16(count);
1191 pSMB->ParameterCount = cpu_to_le16(params);
1192 pSMB->TotalDataCount = pSMB->DataCount;
1193 pSMB->TotalParameterCount = pSMB->ParameterCount;
1194 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1195 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001196 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001197 pSMB->ByteCount = cpu_to_le16(byte_count);
1198 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1199 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1200 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001201 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001202 goto psx_create_err;
1203 }
1204
Joe Perchesf96637b2013-05-04 22:12:25 -05001205 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001206 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1207
Jeff Layton820a8032011-05-04 08:05:26 -04001208 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001209 rc = -EIO; /* bad smb */
1210 goto psx_create_err;
1211 }
1212
1213 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001214 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001215 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001216
Steve French2dd29d32007-04-23 22:07:35 +00001217 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001218 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001219 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1220 /* Let caller know file was created so we can set the mode. */
1221 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001222 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001223 *pOplock |= CIFS_CREATE_ACTION;
1224 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001225 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1226 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001227 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001228 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001229 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001230 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001231 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001232 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001233 goto psx_create_err;
1234 }
Steve French50c2f752007-07-13 00:33:32 +00001235 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001236 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001237 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001238 }
Steve French2dd29d32007-04-23 22:07:35 +00001239
1240psx_create_err:
1241 cifs_buf_release(pSMB);
1242
Steve French65bc98b2009-07-10 15:27:25 +00001243 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001244 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001245 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001246 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001247
1248 if (rc == -EAGAIN)
1249 goto PsxCreat;
1250
Steve French50c2f752007-07-13 00:33:32 +00001251 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001252}
1253
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254static __u16 convert_disposition(int disposition)
1255{
1256 __u16 ofun = 0;
1257
1258 switch (disposition) {
1259 case FILE_SUPERSEDE:
1260 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1261 break;
1262 case FILE_OPEN:
1263 ofun = SMBOPEN_OAPPEND;
1264 break;
1265 case FILE_CREATE:
1266 ofun = SMBOPEN_OCREATE;
1267 break;
1268 case FILE_OPEN_IF:
1269 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1270 break;
1271 case FILE_OVERWRITE:
1272 ofun = SMBOPEN_OTRUNC;
1273 break;
1274 case FILE_OVERWRITE_IF:
1275 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1276 break;
1277 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001278 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 ofun = SMBOPEN_OAPPEND; /* regular open */
1280 }
1281 return ofun;
1282}
1283
Jeff Layton35fc37d2008-05-14 10:22:03 -07001284static int
1285access_flags_to_smbopen_mode(const int access_flags)
1286{
1287 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1288
1289 if (masked_flags == GENERIC_READ)
1290 return SMBOPEN_READ;
1291 else if (masked_flags == GENERIC_WRITE)
1292 return SMBOPEN_WRITE;
1293
1294 /* just go for read/write */
1295 return SMBOPEN_READWRITE;
1296}
1297
Steve Frencha9d02ad2005-08-24 23:06:05 -07001298int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001299SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001300 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001301 const int access_flags, const int create_options, __u16 *netfid,
1302 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 const struct nls_table *nls_codepage, int remap)
1304{
1305 int rc = -EACCES;
1306 OPENX_REQ *pSMB = NULL;
1307 OPENX_RSP *pSMBr = NULL;
1308 int bytes_returned;
1309 int name_len;
1310 __u16 count;
1311
1312OldOpenRetry:
1313 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1314 (void **) &pSMBr);
1315 if (rc)
1316 return rc;
1317
1318 pSMB->AndXCommand = 0xFF; /* none */
1319
1320 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1321 count = 1; /* account for one byte pad to word boundary */
1322 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001323 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1324 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001325 name_len++; /* trailing null */
1326 name_len *= 2;
1327 } else { /* BB improve check for buffer overruns BB */
1328 count = 0; /* no pad */
1329 name_len = strnlen(fileName, PATH_MAX);
1330 name_len++; /* trailing null */
1331 strncpy(pSMB->fileName, fileName, name_len);
1332 }
1333 if (*pOplock & REQ_OPLOCK)
1334 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001335 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001336 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001337
Steve Frencha9d02ad2005-08-24 23:06:05 -07001338 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001339 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001340 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1341 /* set file as system file if special file such
1342 as fifo and server expecting SFU style and
1343 no Unix extensions */
1344
Steve French790fe572007-07-07 19:25:05 +00001345 if (create_options & CREATE_OPTION_SPECIAL)
1346 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001347 else /* BB FIXME BB */
1348 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001349
Jeff Layton67750fb2008-05-09 22:28:02 +00001350 if (create_options & CREATE_OPTION_READONLY)
1351 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001352
1353 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001354/* pSMB->CreateOptions = cpu_to_le32(create_options &
1355 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001356 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001357
1358 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001359 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001360 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001361 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001362
1363 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001364 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001365 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001366 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001367 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001368 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001369 } else {
1370 /* BB verify if wct == 15 */
1371
Steve French582d21e2008-05-13 04:54:12 +00001372/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001373
1374 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1375 /* Let caller know file was created so we can set the mode. */
1376 /* Do we care about the CreateAction in any other cases? */
1377 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001378/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001379 *pOplock |= CIFS_CREATE_ACTION; */
1380 /* BB FIXME END */
1381
Steve French790fe572007-07-07 19:25:05 +00001382 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001383 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1384 pfile_info->LastAccessTime = 0; /* BB fixme */
1385 pfile_info->LastWriteTime = 0; /* BB fixme */
1386 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001387 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001388 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001389 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001390 pfile_info->AllocationSize =
1391 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1392 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001393 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001394 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001395 }
1396 }
1397
1398 cifs_buf_release(pSMB);
1399 if (rc == -EAGAIN)
1400 goto OldOpenRetry;
1401 return rc;
1402}
1403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001405CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1406 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407{
1408 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001409 OPEN_REQ *req = NULL;
1410 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 int bytes_returned;
1412 int name_len;
1413 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001414 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1415 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001416 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001417 const struct nls_table *nls = cifs_sb->local_nls;
1418 int create_options = oparms->create_options;
1419 int desired_access = oparms->desired_access;
1420 int disposition = oparms->disposition;
1421 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
1423openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001424 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1425 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 if (rc)
1427 return rc;
1428
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001429 /* no commands go after this */
1430 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001432 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1433 /* account for one byte pad to word boundary */
1434 count = 1;
1435 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1436 path, PATH_MAX, nls, remap);
1437 /* trailing null */
1438 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001440 req->NameLength = cpu_to_le16(name_len);
1441 } else {
1442 /* BB improve check for buffer overruns BB */
1443 /* no pad */
1444 count = 0;
1445 name_len = strnlen(path, PATH_MAX);
1446 /* trailing null */
1447 name_len++;
1448 req->NameLength = cpu_to_le16(name_len);
1449 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001451
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001452 if (*oplock & REQ_OPLOCK)
1453 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1454 else if (*oplock & REQ_BATCHOPLOCK)
1455 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1456
1457 req->DesiredAccess = cpu_to_le32(desired_access);
1458 req->AllocationSize = 0;
1459
1460 /*
1461 * Set file as system file if special file such as fifo and server
1462 * expecting SFU style and no Unix extensions.
1463 */
1464 if (create_options & CREATE_OPTION_SPECIAL)
1465 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1466 else
1467 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1468
1469 /*
1470 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1471 * sensitive checks for other servers such as Samba.
1472 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001474 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
Jeff Layton67750fb2008-05-09 22:28:02 +00001476 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001477 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001478
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001479 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1480 req->CreateDisposition = cpu_to_le32(disposition);
1481 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1482
Steve French09d1db52005-04-28 22:41:08 -07001483 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001484 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1485 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
1487 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001488 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001490 req->ByteCount = cpu_to_le16(count);
1491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1492 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001493 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001495 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001496 cifs_buf_release(req);
1497 if (rc == -EAGAIN)
1498 goto openRetry;
1499 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001501
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001502 /* 1 byte no need to le_to_cpu */
1503 *oplock = rsp->OplockLevel;
1504 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001505 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001506
1507 /* Let caller know file was created so we can set the mode. */
1508 /* Do we care about the CreateAction in any other cases? */
1509 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1510 *oplock |= CIFS_CREATE_ACTION;
1511
1512 if (buf) {
1513 /* copy from CreationTime to Attributes */
1514 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1515 /* the file_info buf is endian converted by caller */
1516 buf->AllocationSize = rsp->AllocationSize;
1517 buf->EndOfFile = rsp->EndOfFile;
1518 buf->NumberOfLinks = cpu_to_le32(1);
1519 buf->DeletePending = 0;
1520 }
1521
1522 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 return rc;
1524}
1525
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001526/*
1527 * Discard any remaining data in the current SMB. To do this, we borrow the
1528 * current bigbuf.
1529 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001530int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001531cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001532{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001533 unsigned int rfclen = server->pdu_size;
1534 int remaining = rfclen + server->vals->header_preamble_size -
1535 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536
1537 while (remaining > 0) {
1538 int length;
1539
1540 length = cifs_read_from_socket(server, server->bigbuf,
1541 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001542 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543 if (length < 0)
1544 return length;
1545 server->total_read += length;
1546 remaining -= length;
1547 }
1548
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549 return 0;
1550}
1551
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001552static int
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001553__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1554 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001555{
1556 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001557
Pavel Shilovsky350be252017-04-10 10:31:33 -07001558 length = cifs_discard_remaining_data(server);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001559 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001560 mid->resp_buf = server->smallbuf;
1561 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001562 return length;
1563}
1564
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001565static int
1566cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1567{
1568 struct cifs_readdata *rdata = mid->callback_data;
1569
1570 return __cifs_readv_discard(server, mid, rdata->result);
1571}
1572
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001573int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001574cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1575{
1576 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001577 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001578 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001579 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001580 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001581 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001582 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001583
Joe Perchesf96637b2013-05-04 22:12:25 -05001584 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1585 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001586
1587 /*
1588 * read the rest of READ_RSP header (sans Data array), or whatever we
1589 * can if there's not enough data. At this point, we've read down to
1590 * the Mid.
1591 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001592 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001593 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001594
Al Viroa6137302016-01-09 19:37:16 -05001595 length = cifs_read_from_socket(server,
1596 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001597 if (length < 0)
1598 return length;
1599 server->total_read += length;
1600
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001601 if (server->ops->is_session_expired &&
1602 server->ops->is_session_expired(buf)) {
1603 cifs_reconnect(server);
1604 wake_up(&server->response_q);
1605 return -1;
1606 }
1607
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001608 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -08001609 server->ops->is_status_pending(buf, server)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001610 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001611 return -1;
1612 }
1613
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001614 /* set up first two iov for signature check and to get credits */
1615 rdata->iov[0].iov_base = buf;
Pavel Shilovskybb1bccb2019-01-17 16:18:38 -08001616 rdata->iov[0].iov_len = server->vals->header_preamble_size;
1617 rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1618 rdata->iov[1].iov_len =
1619 server->total_read - server->vals->header_preamble_size;
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001620 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1621 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1622 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1623 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1624
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001626 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001627 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001628 cifs_dbg(FYI, "%s: server returned error %d\n",
1629 __func__, rdata->result);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001630 /* normal error on read response */
1631 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001632 }
1633
1634 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001635 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001636 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1637 __func__, server->total_read,
1638 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001639 rdata->result = -EIO;
1640 return cifs_readv_discard(server, mid);
1641 }
1642
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001643 data_offset = server->ops->read_data_offset(buf) +
1644 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001645 if (data_offset < server->total_read) {
1646 /*
1647 * win2k8 sometimes sends an offset of 0 when the read
1648 * is beyond the EOF. Treat it as if the data starts just after
1649 * the header.
1650 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001651 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1652 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001653 data_offset = server->total_read;
1654 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1655 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001656 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1657 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658 rdata->result = -EIO;
1659 return cifs_readv_discard(server, mid);
1660 }
1661
Joe Perchesf96637b2013-05-04 22:12:25 -05001662 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1663 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001664
1665 len = data_offset - server->total_read;
1666 if (len > 0) {
1667 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001668 length = cifs_read_from_socket(server,
1669 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001670 if (length < 0)
1671 return length;
1672 server->total_read += length;
1673 }
1674
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001675 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001676#ifdef CONFIG_CIFS_SMB_DIRECT
1677 use_rdma_mr = rdata->mr;
1678#endif
1679 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1680 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001681 /* data_len is corrupt -- discard frame */
1682 rdata->result = -EIO;
1683 return cifs_readv_discard(server, mid);
1684 }
1685
Jeff Layton8321fec2012-09-19 06:22:32 -07001686 length = rdata->read_into_pages(server, rdata, data_len);
1687 if (length < 0)
1688 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001689
Jeff Layton8321fec2012-09-19 06:22:32 -07001690 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001691
Joe Perchesf96637b2013-05-04 22:12:25 -05001692 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1693 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001694
1695 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001696 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001697 return cifs_readv_discard(server, mid);
1698
1699 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001700 mid->resp_buf = server->smallbuf;
1701 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001702 return length;
1703}
1704
1705static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001706cifs_readv_callback(struct mid_q_entry *mid)
1707{
1708 struct cifs_readdata *rdata = mid->callback_data;
1709 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1710 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001711 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1712 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001713 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001714 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001715 .rq_npages = rdata->nr_pages,
1716 .rq_pagesz = rdata->pagesz,
1717 .rq_tailsz = rdata->tailsz };
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001718 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001719
Joe Perchesf96637b2013-05-04 22:12:25 -05001720 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1721 __func__, mid->mid, mid->mid_state, rdata->result,
1722 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001723
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001724 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001725 case MID_RESPONSE_RECEIVED:
1726 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001727 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001728 int rc = 0;
1729
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001730 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001731 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001732 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001733 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1734 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001735 }
1736 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001737 task_io_account_read(rdata->got_bytes);
1738 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001739 break;
1740 case MID_REQUEST_SUBMITTED:
1741 case MID_RETRY_NEEDED:
1742 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001743 if (server->sign && rdata->got_bytes)
1744 /* reset bytes number since we can not check a sign */
1745 rdata->got_bytes = 0;
1746 /* FIXME: should this be counted toward the initiating task? */
1747 task_io_account_read(rdata->got_bytes);
1748 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001749 break;
1750 default:
1751 rdata->result = -EIO;
1752 }
1753
Jeff Laytonda472fc2012-03-23 14:40:53 -04001754 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001755 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001756 add_credits(server, &credits, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001757}
1758
1759/* cifs_async_readv - send an async write, and set up mid to handle result */
1760int
1761cifs_async_readv(struct cifs_readdata *rdata)
1762{
1763 int rc;
1764 READ_REQ *smb = NULL;
1765 int wct;
1766 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001767 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1768 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001769
Joe Perchesf96637b2013-05-04 22:12:25 -05001770 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1771 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001772
1773 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1774 wct = 12;
1775 else {
1776 wct = 10; /* old style read */
1777 if ((rdata->offset >> 32) > 0) {
1778 /* can not handle this big offset for old */
1779 return -EIO;
1780 }
1781 }
1782
1783 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1784 if (rc)
1785 return rc;
1786
1787 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1788 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1789
1790 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001791 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001792 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1793 if (wct == 12)
1794 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1795 smb->Remaining = 0;
1796 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1797 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1798 if (wct == 12)
1799 smb->ByteCount = 0;
1800 else {
1801 /* old style read */
1802 struct smb_com_readx_req *smbr =
1803 (struct smb_com_readx_req *)smb;
1804 smbr->ByteCount = 0;
1805 }
1806
1807 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001808 rdata->iov[0].iov_base = smb;
1809 rdata->iov[0].iov_len = 4;
1810 rdata->iov[1].iov_base = (char *)smb + 4;
1811 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001812
Jeff Layton6993f742012-05-16 07:13:17 -04001813 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001814 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001815 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001816
1817 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001818 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001819 else
1820 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001821
1822 cifs_small_buf_release(smb);
1823 return rc;
1824}
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001827CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1828 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829{
1830 int rc = -EACCES;
1831 READ_REQ *pSMB = NULL;
1832 READ_RSP *pSMBr = NULL;
1833 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001834 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001835 int resp_buf_type = 0;
1836 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001837 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001838 __u32 pid = io_parms->pid;
1839 __u16 netfid = io_parms->netfid;
1840 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001841 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001842 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Joe Perchesf96637b2013-05-04 22:12:25 -05001844 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001845 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001846 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001847 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001848 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001849 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001850 /* can not handle this big offset for old */
1851 return -EIO;
1852 }
1853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001856 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 if (rc)
1858 return rc;
1859
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001860 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1861 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 /* tcon and ses pointer are checked in smb_init */
1864 if (tcon->ses->server == NULL)
1865 return -ECONNABORTED;
1866
Steve Frenchec637e32005-12-12 20:53:18 -08001867 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001869 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001870 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001871 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001872
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 pSMB->Remaining = 0;
1874 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1875 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001876 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001877 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1878 else {
1879 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001880 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001881 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001882 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001883 }
Steve Frenchec637e32005-12-12 20:53:18 -08001884
1885 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001886 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001887 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1888 CIFS_LOG_ERROR, &rsp_iov);
1889 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001890 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001891 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001893 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 } else {
1895 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1896 data_length = data_length << 16;
1897 data_length += le16_to_cpu(pSMBr->DataLength);
1898 *nbytes = data_length;
1899
1900 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001901 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001903 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001904 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 rc = -EIO;
1906 *nbytes = 0;
1907 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001908 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001909 le16_to_cpu(pSMBr->DataOffset);
1910/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001911 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001912 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001913 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001914 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001915 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 }
1917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
Steve French790fe572007-07-07 19:25:05 +00001919 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001920 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001921 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001922 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001923 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001924 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001925 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001926 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001927 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001928 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001929
1930 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 since file handle passed in no longer valid */
1932 return rc;
1933}
1934
Steve Frenchec637e32005-12-12 20:53:18 -08001935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001937CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001938 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939{
1940 int rc = -EACCES;
1941 WRITE_REQ *pSMB = NULL;
1942 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001943 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 __u32 bytes_sent;
1945 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001946 __u32 pid = io_parms->pid;
1947 __u16 netfid = io_parms->netfid;
1948 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001949 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001950 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Steve Frencha24e2d72010-04-03 17:20:21 +00001952 *nbytes = 0;
1953
Joe Perchesf96637b2013-05-04 22:12:25 -05001954 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001955 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001956 return -ECONNABORTED;
1957
Steve French790fe572007-07-07 19:25:05 +00001958 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001959 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001960 else {
Steve French1c955182005-08-30 20:58:07 -07001961 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001962 if ((offset >> 32) > 0) {
1963 /* can not handle big offset for old srv */
1964 return -EIO;
1965 }
1966 }
Steve French1c955182005-08-30 20:58:07 -07001967
1968 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 (void **) &pSMBr);
1970 if (rc)
1971 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001972
1973 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1974 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 /* tcon and ses pointer are checked in smb_init */
1977 if (tcon->ses->server == NULL)
1978 return -ECONNABORTED;
1979
1980 pSMB->AndXCommand = 0xFF; /* none */
1981 pSMB->Fid = netfid;
1982 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001983 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001984 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001985
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 pSMB->Reserved = 0xFFFFFFFF;
1987 pSMB->WriteMode = 0;
1988 pSMB->Remaining = 0;
1989
Steve French50c2f752007-07-13 00:33:32 +00001990 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 can send more if LARGE_WRITE_X capability returned by the server and if
1992 our buffer is big enough or if we convert to iovecs on socket writes
1993 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001994 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1996 } else {
1997 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1998 & ~0xFF;
1999 }
2000
2001 if (bytes_sent > count)
2002 bytes_sent = count;
2003 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002004 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00002005 if (buf)
Steve French61e74802008-12-03 00:57:54 +00002006 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04002007 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 /* No buffer */
2009 cifs_buf_release(pSMB);
2010 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07002011 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00002012 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07002013 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00002014 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07002015 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00002016
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
2018 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002019 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07002020
Steve French790fe572007-07-07 19:25:05 +00002021 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07002022 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00002023 else { /* old style write has byte count 4 bytes earlier
2024 so 4 bytes pad */
2025 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07002026 (struct smb_com_writex_req *)pSMB;
2027 pSMBW->ByteCount = cpu_to_le16(byte_count);
2028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04002031 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002032 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002034 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 } else {
2036 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2037 *nbytes = (*nbytes) << 16;
2038 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302039
2040 /*
2041 * Mask off high 16 bits when bytes written as returned by the
2042 * server is greater than bytes requested by the client. Some
2043 * OS/2 servers are known to set incorrect CountHigh values.
2044 */
2045 if (*nbytes > count)
2046 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 }
2048
2049 cifs_buf_release(pSMB);
2050
Steve French50c2f752007-07-13 00:33:32 +00002051 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 since file handle passed in no longer valid */
2053
2054 return rc;
2055}
2056
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002057void
2058cifs_writedata_release(struct kref *refcount)
2059{
2060 struct cifs_writedata *wdata = container_of(refcount,
2061 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07002062#ifdef CONFIG_CIFS_SMB_DIRECT
2063 if (wdata->mr) {
2064 smbd_deregister_mr(wdata->mr);
2065 wdata->mr = NULL;
2066 }
2067#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002068
2069 if (wdata->cfile)
2070 cifsFileInfo_put(wdata->cfile);
2071
Long Li8e7360f2018-05-30 12:47:56 -07002072 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002073 kfree(wdata);
2074}
2075
2076/*
2077 * Write failed with a retryable error. Resend the write request. It's also
2078 * possible that the page was redirtied so re-clean the page.
2079 */
2080static void
2081cifs_writev_requeue(struct cifs_writedata *wdata)
2082{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002083 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00002084 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07002085 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002086 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002087
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002088 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
2089 i = 0;
2090 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002091 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002092 struct cifs_writedata *wdata2;
2093 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002095 wsize = server->ops->wp_retry_size(inode);
2096 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002097 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002098 if (!nr_pages) {
2099 rc = -ENOTSUPP;
2100 break;
2101 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002102 cur_len = nr_pages * PAGE_SIZE;
2103 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002104 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002105 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002106 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002107 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06002108 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002109
2110 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2111 if (!wdata2) {
2112 rc = -ENOMEM;
2113 break;
2114 }
2115
2116 for (j = 0; j < nr_pages; j++) {
2117 wdata2->pages[j] = wdata->pages[i + j];
2118 lock_page(wdata2->pages[j]);
2119 clear_page_dirty_for_io(wdata2->pages[j]);
2120 }
2121
2122 wdata2->sync_mode = wdata->sync_mode;
2123 wdata2->nr_pages = nr_pages;
2124 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002125 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002126 wdata2->tailsz = tailsz;
2127 wdata2->bytes = cur_len;
2128
2129 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2130 if (!wdata2->cfile) {
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002131 cifs_dbg(VFS, "No writable handle to retry writepages\n");
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002132 rc = -EBADF;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002133 } else {
2134 wdata2->pid = wdata2->cfile->pid;
2135 rc = server->ops->async_writev(wdata2,
2136 cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002137 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002138
2139 for (j = 0; j < nr_pages; j++) {
2140 unlock_page(wdata2->pages[j]);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002141 if (rc != 0 && !is_retryable_error(rc)) {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002142 SetPageError(wdata2->pages[j]);
2143 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002144 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002145 }
2146 }
2147
2148 if (rc) {
2149 kref_put(&wdata2->refcount, cifs_writedata_release);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002150 if (is_retryable_error(rc))
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002151 continue;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002152 i += nr_pages;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002153 break;
2154 }
2155
2156 rest_len -= cur_len;
2157 i += nr_pages;
2158 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002159
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002160 /* cleanup remaining pages from the original wdata */
2161 for (; i < wdata->nr_pages; i++) {
2162 SetPageError(wdata->pages[i]);
2163 end_page_writeback(wdata->pages[i]);
2164 put_page(wdata->pages[i]);
2165 }
2166
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002167 if (rc != 0 && !is_retryable_error(rc))
2168 mapping_set_error(inode->i_mapping, rc);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169 kref_put(&wdata->refcount, cifs_writedata_release);
2170}
2171
Jeff Laytonc2e87642012-03-23 14:40:55 -04002172void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002173cifs_writev_complete(struct work_struct *work)
2174{
2175 struct cifs_writedata *wdata = container_of(work,
2176 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002177 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002178 int i = 0;
2179
2180 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002181 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002182 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002183 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002184 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2185 wdata->bytes);
2186 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2187 return cifs_writev_requeue(wdata);
2188
2189 for (i = 0; i < wdata->nr_pages; i++) {
2190 struct page *page = wdata->pages[i];
2191 if (wdata->result == -EAGAIN)
2192 __set_page_dirty_nobuffers(page);
2193 else if (wdata->result < 0)
2194 SetPageError(page);
2195 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002196 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002197 }
2198 if (wdata->result != -EAGAIN)
2199 mapping_set_error(inode->i_mapping, wdata->result);
2200 kref_put(&wdata->refcount, cifs_writedata_release);
2201}
2202
2203struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002204cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002205{
Long Li8e7360f2018-05-30 12:47:56 -07002206 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002207 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002208 if (pages)
2209 return cifs_writedata_direct_alloc(pages, complete);
2210
2211 return NULL;
2212}
2213
2214struct cifs_writedata *
2215cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2216{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002217 struct cifs_writedata *wdata;
2218
Long Li8e7360f2018-05-30 12:47:56 -07002219 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002220 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002221 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002222 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002223 INIT_LIST_HEAD(&wdata->list);
2224 init_completion(&wdata->done);
2225 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002226 }
2227 return wdata;
2228}
2229
2230/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002231 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002232 * workqueue completion task.
2233 */
2234static void
2235cifs_writev_callback(struct mid_q_entry *mid)
2236{
2237 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002238 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002239 unsigned int written;
2240 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002241 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002242
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002243 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002244 case MID_RESPONSE_RECEIVED:
2245 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2246 if (wdata->result != 0)
2247 break;
2248
2249 written = le16_to_cpu(smb->CountHigh);
2250 written <<= 16;
2251 written += le16_to_cpu(smb->Count);
2252 /*
2253 * Mask off high 16 bits when bytes written as returned
2254 * by the server is greater than bytes requested by the
2255 * client. OS/2 servers are known to set incorrect
2256 * CountHigh values.
2257 */
2258 if (written > wdata->bytes)
2259 written &= 0xFFFF;
2260
2261 if (written < wdata->bytes)
2262 wdata->result = -ENOSPC;
2263 else
2264 wdata->bytes = written;
2265 break;
2266 case MID_REQUEST_SUBMITTED:
2267 case MID_RETRY_NEEDED:
2268 wdata->result = -EAGAIN;
2269 break;
2270 default:
2271 wdata->result = -EIO;
2272 break;
2273 }
2274
Jeff Laytonda472fc2012-03-23 14:40:53 -04002275 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002276 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002277 add_credits(tcon->ses->server, &credits, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002278}
2279
2280/* cifs_async_writev - send an async write, and set up mid to handle result */
2281int
Steve French4a5c80d2014-02-07 20:45:12 -06002282cifs_async_writev(struct cifs_writedata *wdata,
2283 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002284{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002285 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002286 WRITE_REQ *smb = NULL;
2287 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002288 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002289 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002290 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002291
2292 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2293 wct = 14;
2294 } else {
2295 wct = 12;
2296 if (wdata->offset >> 32 > 0) {
2297 /* can not handle big offset for old srv */
2298 return -EIO;
2299 }
2300 }
2301
2302 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2303 if (rc)
2304 goto async_writev_out;
2305
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002306 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2307 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002308
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002309 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002310 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002311 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2312 if (wct == 14)
2313 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2314 smb->Reserved = 0xFFFFFFFF;
2315 smb->WriteMode = 0;
2316 smb->Remaining = 0;
2317
2318 smb->DataOffset =
2319 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2320
2321 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002322 iov[0].iov_len = 4;
2323 iov[0].iov_base = smb;
2324 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2325 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002326
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002327 rqst.rq_iov = iov;
2328 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002329 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002330 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002331 rqst.rq_npages = wdata->nr_pages;
2332 rqst.rq_pagesz = wdata->pagesz;
2333 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002334
Joe Perchesf96637b2013-05-04 22:12:25 -05002335 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2336 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002337
2338 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2339 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2340
2341 if (wct == 14) {
2342 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2343 put_bcc(wdata->bytes + 1, &smb->hdr);
2344 } else {
2345 /* wct == 12 */
2346 struct smb_com_writex_req *smbw =
2347 (struct smb_com_writex_req *)smb;
2348 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2349 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002350 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002351 }
2352
2353 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002354 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002355 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002356
2357 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002358 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002359 else
Steve French4a5c80d2014-02-07 20:45:12 -06002360 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002361
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002362async_writev_out:
2363 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002364 return rc;
2365}
2366
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002367int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002368CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002369 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370{
2371 int rc = -EACCES;
2372 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002373 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002374 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002375 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002376 __u32 pid = io_parms->pid;
2377 __u16 netfid = io_parms->netfid;
2378 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002379 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002380 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002381 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002383 *nbytes = 0;
2384
Joe Perchesf96637b2013-05-04 22:12:25 -05002385 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002386
Steve French4c3130e2008-12-09 00:28:16 +00002387 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002388 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002389 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002390 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002391 if ((offset >> 32) > 0) {
2392 /* can not handle big offset for old srv */
2393 return -EIO;
2394 }
2395 }
Steve French8cc64c62005-10-03 13:49:43 -07002396 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 if (rc)
2398 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002399
2400 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2401 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 /* tcon and ses pointer are checked in smb_init */
2404 if (tcon->ses->server == NULL)
2405 return -ECONNABORTED;
2406
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002407 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 pSMB->Fid = netfid;
2409 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002410 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002411 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 pSMB->Reserved = 0xFFFFFFFF;
2413 pSMB->WriteMode = 0;
2414 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002415
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002417 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Steve French3e844692005-10-03 13:37:24 -07002419 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2420 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002421 /* header + 1 byte pad */
2422 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002423 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002424 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002425 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002426 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002427 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002428 pSMB->ByteCount = cpu_to_le16(count + 1);
2429 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002430 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002431 (struct smb_com_writex_req *)pSMB;
2432 pSMBW->ByteCount = cpu_to_le16(count + 5);
2433 }
Steve French3e844692005-10-03 13:37:24 -07002434 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002435 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002436 iov[0].iov_len = smb_hdr_len + 4;
2437 else /* wct == 12 pad bigger by four bytes */
2438 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002439
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002440 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2441 &rsp_iov);
2442 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002443 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002445 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002446 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002447 /* presumably this can not happen, but best to be safe */
2448 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002449 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002450 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002451 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2452 *nbytes = (*nbytes) << 16;
2453 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302454
2455 /*
2456 * Mask off high 16 bits when bytes written as returned by the
2457 * server is greater than bytes requested by the client. OS/2
2458 * servers are known to set incorrect CountHigh values.
2459 */
2460 if (*nbytes > count)
2461 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002464 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Steve French50c2f752007-07-13 00:33:32 +00002466 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 since file handle passed in no longer valid */
2468
2469 return rc;
2470}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002471
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002472int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2473 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002474 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2475{
2476 int rc = 0;
2477 LOCK_REQ *pSMB = NULL;
2478 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002479 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002480 int resp_buf_type;
2481 __u16 count;
2482
Joe Perchesf96637b2013-05-04 22:12:25 -05002483 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2484 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002485
2486 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2487 if (rc)
2488 return rc;
2489
2490 pSMB->Timeout = 0;
2491 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2492 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2493 pSMB->LockType = lock_type;
2494 pSMB->AndXCommand = 0xFF; /* none */
2495 pSMB->Fid = netfid; /* netfid stays le */
2496
2497 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2498 inc_rfc1001_len(pSMB, count);
2499 pSMB->ByteCount = cpu_to_le16(count);
2500
2501 iov[0].iov_base = (char *)pSMB;
2502 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2503 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2504 iov[1].iov_base = (char *)buf;
2505 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2506
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002507 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002508 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2509 &rsp_iov);
2510 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002511 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002512 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002513
2514 return rc;
2515}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002516
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002518CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002519 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002521 const __u32 numLock, const __u8 lockType,
2522 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
2524 int rc = 0;
2525 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002526/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002528 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 __u16 count;
2530
Joe Perchesf96637b2013-05-04 22:12:25 -05002531 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2532 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002533 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2534
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 if (rc)
2536 return rc;
2537
Steve French790fe572007-07-07 19:25:05 +00002538 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002539 /* no response expected */
2540 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002542 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002543 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2545 } else {
2546 pSMB->Timeout = 0;
2547 }
2548
2549 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2550 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2551 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002552 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 pSMB->AndXCommand = 0xFF; /* none */
2554 pSMB->Fid = smb_file_id; /* netfid stays le */
2555
Steve French790fe572007-07-07 19:25:05 +00002556 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002557 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 /* BB where to store pid high? */
2559 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2560 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2561 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2562 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2563 count = sizeof(LOCKING_ANDX_RANGE);
2564 } else {
2565 /* oplock break */
2566 count = 0;
2567 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002568 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 pSMB->ByteCount = cpu_to_le16(count);
2570
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002571 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002572 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002573 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002574 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002575 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002576 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002577 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002578 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002579 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
Steve French50c2f752007-07-13 00:33:32 +00002581 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 since file handle passed in no longer valid */
2583 return rc;
2584}
2585
2586int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002587CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002588 const __u16 smb_file_id, const __u32 netpid,
2589 const loff_t start_offset, const __u64 len,
2590 struct file_lock *pLockData, const __u16 lock_type,
2591 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002592{
2593 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2594 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002595 struct cifs_posix_lock *parm_data;
2596 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002597 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002598 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002599 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002600 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002601 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002602 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002603
Joe Perchesf96637b2013-05-04 22:12:25 -05002604 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002605
Steve French08547b02006-02-28 22:39:25 +00002606 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2607
2608 if (rc)
2609 return rc;
2610
2611 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2612
Steve French50c2f752007-07-13 00:33:32 +00002613 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002614 pSMB->MaxSetupCount = 0;
2615 pSMB->Reserved = 0;
2616 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002617 pSMB->Reserved2 = 0;
2618 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2619 offset = param_offset + params;
2620
Steve French08547b02006-02-28 22:39:25 +00002621 count = sizeof(struct cifs_posix_lock);
2622 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002623 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002624 pSMB->SetupCount = 1;
2625 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002626 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002627 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2628 else
2629 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2630 byte_count = 3 /* pad */ + params + count;
2631 pSMB->DataCount = cpu_to_le16(count);
2632 pSMB->ParameterCount = cpu_to_le16(params);
2633 pSMB->TotalDataCount = pSMB->DataCount;
2634 pSMB->TotalParameterCount = pSMB->ParameterCount;
2635 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002636 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002637 (((char *) &pSMB->hdr.Protocol) + offset);
2638
2639 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002640 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002641 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002642 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002643 pSMB->Timeout = cpu_to_le32(-1);
2644 } else
2645 pSMB->Timeout = 0;
2646
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002647 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002648 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002649 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002650
2651 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002652 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002653 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2654 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002655 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002656 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002657 if (waitFlag) {
2658 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2659 (struct smb_hdr *) pSMBr, &bytes_returned);
2660 } else {
Steve French133672e2007-11-13 22:41:37 +00002661 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002662 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002663 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002664 &resp_buf_type, timeout, &rsp_iov);
2665 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002666 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002667 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002668
Steve French08547b02006-02-28 22:39:25 +00002669 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002670 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002671 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002672 /* lock structure can be returned on get */
2673 __u16 data_offset;
2674 __u16 data_count;
2675 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002676
Jeff Layton820a8032011-05-04 08:05:26 -04002677 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002678 rc = -EIO; /* bad smb */
2679 goto plk_err_exit;
2680 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002681 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2682 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002683 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002684 rc = -EIO;
2685 goto plk_err_exit;
2686 }
2687 parm_data = (struct cifs_posix_lock *)
2688 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002689 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002690 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002691 else {
2692 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002693 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002694 pLockData->fl_type = F_RDLCK;
2695 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002696 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002697 pLockData->fl_type = F_WRLCK;
2698
Steve French5443d132011-03-13 05:08:25 +00002699 pLockData->fl_start = le64_to_cpu(parm_data->start);
2700 pLockData->fl_end = pLockData->fl_start +
2701 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002702 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002703 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002704 }
Steve French50c2f752007-07-13 00:33:32 +00002705
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002706plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002707 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002708
Steve French08547b02006-02-28 22:39:25 +00002709 /* Note: On -EAGAIN error only caller can retry on handle based calls
2710 since file handle passed in no longer valid */
2711
2712 return rc;
2713}
2714
2715
2716int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002717CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718{
2719 int rc = 0;
2720 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002721 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723/* do not retry on dead session on close */
2724 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002725 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 return 0;
2727 if (rc)
2728 return rc;
2729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002731 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002733 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002734 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002735 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002737 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002739 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 }
2741 }
2742
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002744 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 rc = 0;
2746
2747 return rc;
2748}
2749
2750int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002751CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002752{
2753 int rc = 0;
2754 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002755 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002756
2757 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2758 if (rc)
2759 return rc;
2760
2761 pSMB->FileID = (__u16) smb_file_id;
2762 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002763 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002764 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002765 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002766 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002767 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002768
2769 return rc;
2770}
2771
2772int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002773CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002774 const char *from_name, const char *to_name,
2775 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776{
2777 int rc = 0;
2778 RENAME_REQ *pSMB = NULL;
2779 RENAME_RSP *pSMBr = NULL;
2780 int bytes_returned;
2781 int name_len, name_len2;
2782 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002783 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Joe Perchesf96637b2013-05-04 22:12:25 -05002785 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786renameRetry:
2787 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2788 (void **) &pSMBr);
2789 if (rc)
2790 return rc;
2791
2792 pSMB->BufferFormat = 0x04;
2793 pSMB->SearchAttributes =
2794 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2795 ATTR_DIRECTORY);
2796
2797 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002798 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2799 from_name, PATH_MAX,
2800 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 name_len++; /* trailing null */
2802 name_len *= 2;
2803 pSMB->OldFileName[name_len] = 0x04; /* pad */
2804 /* protocol requires ASCII signature byte on Unicode string */
2805 pSMB->OldFileName[name_len + 1] = 0x00;
2806 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002807 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002808 to_name, PATH_MAX, cifs_sb->local_nls,
2809 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2811 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002812 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002813 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002815 strncpy(pSMB->OldFileName, from_name, name_len);
2816 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len2++; /* trailing null */
2818 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002819 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 name_len2++; /* trailing null */
2821 name_len2++; /* signature byte */
2822 }
2823
2824 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002825 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 pSMB->ByteCount = cpu_to_le16(count);
2827
2828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002830 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002831 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002832 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 cifs_buf_release(pSMB);
2835
2836 if (rc == -EAGAIN)
2837 goto renameRetry;
2838
2839 return rc;
2840}
2841
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002842int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002843 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002844 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845{
2846 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2847 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002848 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 char *data_offset;
2850 char dummy_string[30];
2851 int rc = 0;
2852 int bytes_returned = 0;
2853 int len_of_str;
2854 __u16 params, param_offset, offset, count, byte_count;
2855
Joe Perchesf96637b2013-05-04 22:12:25 -05002856 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2858 (void **) &pSMBr);
2859 if (rc)
2860 return rc;
2861
2862 params = 6;
2863 pSMB->MaxSetupCount = 0;
2864 pSMB->Reserved = 0;
2865 pSMB->Flags = 0;
2866 pSMB->Timeout = 0;
2867 pSMB->Reserved2 = 0;
2868 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2869 offset = param_offset + params;
2870
2871 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2872 rename_info = (struct set_file_rename *) data_offset;
2873 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002874 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 pSMB->SetupCount = 1;
2876 pSMB->Reserved3 = 0;
2877 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2878 byte_count = 3 /* pad */ + params;
2879 pSMB->ParameterCount = cpu_to_le16(params);
2880 pSMB->TotalParameterCount = pSMB->ParameterCount;
2881 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2882 pSMB->DataOffset = cpu_to_le16(offset);
2883 /* construct random name ".cifs_tmp<inodenum><mid>" */
2884 rename_info->overwrite = cpu_to_le32(1);
2885 rename_info->root_fid = 0;
2886 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002887 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002888 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002889 len_of_str =
2890 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002891 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002893 len_of_str =
2894 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002895 target_name, PATH_MAX, nls_codepage,
2896 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 }
2898 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002899 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 byte_count += count;
2901 pSMB->DataCount = cpu_to_le16(count);
2902 pSMB->TotalDataCount = pSMB->DataCount;
2903 pSMB->Fid = netfid;
2904 pSMB->InformationLevel =
2905 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2906 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002907 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 pSMB->ByteCount = cpu_to_le16(byte_count);
2909 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002911 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002912 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002913 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2914 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002915
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 cifs_buf_release(pSMB);
2917
2918 /* Note: On -EAGAIN error only caller can retry on handle based calls
2919 since file handle passed in no longer valid */
2920
2921 return rc;
2922}
2923
2924int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002925CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2926 const char *fromName, const __u16 target_tid, const char *toName,
2927 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928{
2929 int rc = 0;
2930 COPY_REQ *pSMB = NULL;
2931 COPY_RSP *pSMBr = NULL;
2932 int bytes_returned;
2933 int name_len, name_len2;
2934 __u16 count;
2935
Joe Perchesf96637b2013-05-04 22:12:25 -05002936 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937copyRetry:
2938 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2939 (void **) &pSMBr);
2940 if (rc)
2941 return rc;
2942
2943 pSMB->BufferFormat = 0x04;
2944 pSMB->Tid2 = target_tid;
2945
2946 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2947
2948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002949 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2950 fromName, PATH_MAX, nls_codepage,
2951 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 name_len++; /* trailing null */
2953 name_len *= 2;
2954 pSMB->OldFileName[name_len] = 0x04; /* pad */
2955 /* protocol requires ASCII signature byte on Unicode string */
2956 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002957 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002958 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2959 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2961 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002962 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 name_len = strnlen(fromName, PATH_MAX);
2964 name_len++; /* trailing null */
2965 strncpy(pSMB->OldFileName, fromName, name_len);
2966 name_len2 = strnlen(toName, PATH_MAX);
2967 name_len2++; /* trailing null */
2968 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2969 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2970 name_len2++; /* trailing null */
2971 name_len2++; /* signature byte */
2972 }
2973
2974 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002975 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 pSMB->ByteCount = cpu_to_le16(count);
2977
2978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2980 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002981 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2982 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 }
Steve French0d817bc2008-05-22 02:02:03 +00002984 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
2986 if (rc == -EAGAIN)
2987 goto copyRetry;
2988
2989 return rc;
2990}
2991
2992int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002993CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002995 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996{
2997 TRANSACTION2_SPI_REQ *pSMB = NULL;
2998 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2999 char *data_offset;
3000 int name_len;
3001 int name_len_target;
3002 int rc = 0;
3003 int bytes_returned = 0;
3004 __u16 params, param_offset, offset, byte_count;
3005
Joe Perchesf96637b2013-05-04 22:12:25 -05003006 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007createSymLinkRetry:
3008 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3009 (void **) &pSMBr);
3010 if (rc)
3011 return rc;
3012
3013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3014 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003015 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
3016 /* find define for this maxpathcomponent */
3017 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 name_len++; /* trailing null */
3019 name_len *= 2;
3020
Steve French50c2f752007-07-13 00:33:32 +00003021 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 name_len = strnlen(fromName, PATH_MAX);
3023 name_len++; /* trailing null */
3024 strncpy(pSMB->FileName, fromName, name_len);
3025 }
3026 params = 6 + name_len;
3027 pSMB->MaxSetupCount = 0;
3028 pSMB->Reserved = 0;
3029 pSMB->Flags = 0;
3030 pSMB->Timeout = 0;
3031 pSMB->Reserved2 = 0;
3032 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003033 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 offset = param_offset + params;
3035
3036 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3037 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3038 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003039 cifsConvertToUTF16((__le16 *) data_offset, toName,
3040 /* find define for this maxpathcomponent */
3041 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 name_len_target++; /* trailing null */
3043 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003044 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 name_len_target = strnlen(toName, PATH_MAX);
3046 name_len_target++; /* trailing null */
3047 strncpy(data_offset, toName, name_len_target);
3048 }
3049
3050 pSMB->MaxParameterCount = cpu_to_le16(2);
3051 /* BB find exact max on data count below from sess */
3052 pSMB->MaxDataCount = cpu_to_le16(1000);
3053 pSMB->SetupCount = 1;
3054 pSMB->Reserved3 = 0;
3055 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3056 byte_count = 3 /* pad */ + params + name_len_target;
3057 pSMB->DataCount = cpu_to_le16(name_len_target);
3058 pSMB->ParameterCount = cpu_to_le16(params);
3059 pSMB->TotalDataCount = pSMB->DataCount;
3060 pSMB->TotalParameterCount = pSMB->ParameterCount;
3061 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3062 pSMB->DataOffset = cpu_to_le16(offset);
3063 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
3064 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003065 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 pSMB->ByteCount = cpu_to_le16(byte_count);
3067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003069 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003070 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003071 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
3072 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073
Steve French0d817bc2008-05-22 02:02:03 +00003074 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075
3076 if (rc == -EAGAIN)
3077 goto createSymLinkRetry;
3078
3079 return rc;
3080}
3081
3082int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003083CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07003085 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086{
3087 TRANSACTION2_SPI_REQ *pSMB = NULL;
3088 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3089 char *data_offset;
3090 int name_len;
3091 int name_len_target;
3092 int rc = 0;
3093 int bytes_returned = 0;
3094 __u16 params, param_offset, offset, byte_count;
3095
Joe Perchesf96637b2013-05-04 22:12:25 -05003096 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097createHardLinkRetry:
3098 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3099 (void **) &pSMBr);
3100 if (rc)
3101 return rc;
3102
3103 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06003104 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
3105 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 name_len++; /* trailing null */
3107 name_len *= 2;
3108
Steve French50c2f752007-07-13 00:33:32 +00003109 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 name_len = strnlen(toName, PATH_MAX);
3111 name_len++; /* trailing null */
3112 strncpy(pSMB->FileName, toName, name_len);
3113 }
3114 params = 6 + name_len;
3115 pSMB->MaxSetupCount = 0;
3116 pSMB->Reserved = 0;
3117 pSMB->Flags = 0;
3118 pSMB->Timeout = 0;
3119 pSMB->Reserved2 = 0;
3120 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003121 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 offset = param_offset + params;
3123
3124 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3125 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3126 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003127 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3128 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 name_len_target++; /* trailing null */
3130 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003131 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 name_len_target = strnlen(fromName, PATH_MAX);
3133 name_len_target++; /* trailing null */
3134 strncpy(data_offset, fromName, name_len_target);
3135 }
3136
3137 pSMB->MaxParameterCount = cpu_to_le16(2);
3138 /* BB find exact max on data count below from sess*/
3139 pSMB->MaxDataCount = cpu_to_le16(1000);
3140 pSMB->SetupCount = 1;
3141 pSMB->Reserved3 = 0;
3142 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3143 byte_count = 3 /* pad */ + params + name_len_target;
3144 pSMB->ParameterCount = cpu_to_le16(params);
3145 pSMB->TotalParameterCount = pSMB->ParameterCount;
3146 pSMB->DataCount = cpu_to_le16(name_len_target);
3147 pSMB->TotalDataCount = pSMB->DataCount;
3148 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3149 pSMB->DataOffset = cpu_to_le16(offset);
3150 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3151 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003152 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 pSMB->ByteCount = cpu_to_le16(byte_count);
3154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3155 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003156 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003157 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003158 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3159 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
3161 cifs_buf_release(pSMB);
3162 if (rc == -EAGAIN)
3163 goto createHardLinkRetry;
3164
3165 return rc;
3166}
3167
3168int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003169CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003170 const char *from_name, const char *to_name,
3171 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172{
3173 int rc = 0;
3174 NT_RENAME_REQ *pSMB = NULL;
3175 RENAME_RSP *pSMBr = NULL;
3176 int bytes_returned;
3177 int name_len, name_len2;
3178 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003179 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
Joe Perchesf96637b2013-05-04 22:12:25 -05003181 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182winCreateHardLinkRetry:
3183
3184 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3185 (void **) &pSMBr);
3186 if (rc)
3187 return rc;
3188
3189 pSMB->SearchAttributes =
3190 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3191 ATTR_DIRECTORY);
3192 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3193 pSMB->ClusterCount = 0;
3194
3195 pSMB->BufferFormat = 0x04;
3196
3197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3198 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003199 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3200 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 name_len++; /* trailing null */
3202 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003203
3204 /* protocol specifies ASCII buffer format (0x04) for unicode */
3205 pSMB->OldFileName[name_len] = 0x04;
3206 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003208 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003209 to_name, PATH_MAX, cifs_sb->local_nls,
3210 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3212 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003213 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003214 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003216 strncpy(pSMB->OldFileName, from_name, name_len);
3217 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 name_len2++; /* trailing null */
3219 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003220 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 name_len2++; /* trailing null */
3222 name_len2++; /* signature byte */
3223 }
3224
3225 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003226 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 pSMB->ByteCount = cpu_to_le16(count);
3228
3229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003231 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003232 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003233 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003234
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 cifs_buf_release(pSMB);
3236 if (rc == -EAGAIN)
3237 goto winCreateHardLinkRetry;
3238
3239 return rc;
3240}
3241
3242int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003243CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003244 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003245 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246{
3247/* SMB_QUERY_FILE_UNIX_LINK */
3248 TRANSACTION2_QPI_REQ *pSMB = NULL;
3249 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3250 int rc = 0;
3251 int bytes_returned;
3252 int name_len;
3253 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003254 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
Joe Perchesf96637b2013-05-04 22:12:25 -05003256 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
3258querySymLinkRetry:
3259 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3260 (void **) &pSMBr);
3261 if (rc)
3262 return rc;
3263
3264 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3265 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003266 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3267 searchName, PATH_MAX, nls_codepage,
3268 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 name_len++; /* trailing null */
3270 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003271 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 name_len = strnlen(searchName, PATH_MAX);
3273 name_len++; /* trailing null */
3274 strncpy(pSMB->FileName, searchName, name_len);
3275 }
3276
3277 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3278 pSMB->TotalDataCount = 0;
3279 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003280 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 pSMB->MaxSetupCount = 0;
3282 pSMB->Reserved = 0;
3283 pSMB->Flags = 0;
3284 pSMB->Timeout = 0;
3285 pSMB->Reserved2 = 0;
3286 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003287 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 pSMB->DataCount = 0;
3289 pSMB->DataOffset = 0;
3290 pSMB->SetupCount = 1;
3291 pSMB->Reserved3 = 0;
3292 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3293 byte_count = params + 1 /* pad */ ;
3294 pSMB->TotalParameterCount = cpu_to_le16(params);
3295 pSMB->ParameterCount = pSMB->TotalParameterCount;
3296 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3297 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003298 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 pSMB->ByteCount = cpu_to_le16(byte_count);
3300
3301 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3302 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3303 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003304 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 } else {
3306 /* decode response */
3307
3308 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003310 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003311 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003313 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003314 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315
Jeff Layton460b9692009-04-30 07:17:56 -04003316 data_start = ((char *) &pSMBr->hdr.Protocol) +
3317 le16_to_cpu(pSMBr->t2.DataOffset);
3318
Steve French0e0d2cf2009-05-01 05:27:32 +00003319 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3320 is_unicode = true;
3321 else
3322 is_unicode = false;
3323
Steve French737b7582005-04-28 22:41:06 -07003324 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003325 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3326 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003327 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003328 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 }
3330 }
3331 cifs_buf_release(pSMB);
3332 if (rc == -EAGAIN)
3333 goto querySymLinkRetry;
3334 return rc;
3335}
3336
Steve Frenchc52a95542011-02-24 06:16:22 +00003337/*
3338 * Recent Windows versions now create symlinks more frequently
3339 * and they use the "reparse point" mechanism below. We can of course
3340 * do symlinks nicely to Samba and other servers which support the
3341 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3342 * "MF" symlinks optionally, but for recent Windows we really need to
3343 * reenable the code below and fix the cifs_symlink callers to handle this.
3344 * In the interim this code has been moved to its own config option so
3345 * it is not compiled in by default until callers fixed up and more tested.
3346 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003348CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3349 __u16 fid, char **symlinkinfo,
3350 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351{
3352 int rc = 0;
3353 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003354 struct smb_com_transaction_ioctl_req *pSMB;
3355 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003356 bool is_unicode;
3357 unsigned int sub_len;
3358 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003359 struct reparse_symlink_data *reparse_buf;
3360 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003361 __u32 data_offset, data_count;
3362 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003364 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3366 (void **) &pSMBr);
3367 if (rc)
3368 return rc;
3369
3370 pSMB->TotalParameterCount = 0 ;
3371 pSMB->TotalDataCount = 0;
3372 pSMB->MaxParameterCount = cpu_to_le32(2);
3373 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003374 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 pSMB->MaxSetupCount = 4;
3376 pSMB->Reserved = 0;
3377 pSMB->ParameterOffset = 0;
3378 pSMB->DataCount = 0;
3379 pSMB->DataOffset = 0;
3380 pSMB->SetupCount = 4;
3381 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3382 pSMB->ParameterCount = pSMB->TotalParameterCount;
3383 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3384 pSMB->IsFsctl = 1; /* FSCTL */
3385 pSMB->IsRootFlag = 0;
3386 pSMB->Fid = fid; /* file handle always le */
3387 pSMB->ByteCount = 0;
3388
3389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3391 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003392 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003393 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 }
Steve French989c7e52009-05-02 05:32:20 +00003395
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003396 data_offset = le32_to_cpu(pSMBr->DataOffset);
3397 data_count = le32_to_cpu(pSMBr->DataCount);
3398 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3399 /* BB also check enough total bytes returned */
3400 rc = -EIO; /* bad smb */
3401 goto qreparse_out;
3402 }
3403 if (!data_count || (data_count > 2048)) {
3404 rc = -EIO;
3405 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3406 goto qreparse_out;
3407 }
3408 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003409 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003410 ((char *)&pSMBr->hdr.Protocol + data_offset);
3411 if ((char *)reparse_buf >= end_of_smb) {
3412 rc = -EIO;
3413 goto qreparse_out;
3414 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003415 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3416 cifs_dbg(FYI, "NFS style reparse tag\n");
3417 posix_buf = (struct reparse_posix_data *)reparse_buf;
3418
3419 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3420 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3421 le64_to_cpu(posix_buf->InodeType));
3422 rc = -EOPNOTSUPP;
3423 goto qreparse_out;
3424 }
3425 is_unicode = true;
3426 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3427 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3428 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3429 rc = -EIO;
3430 goto qreparse_out;
3431 }
3432 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3433 sub_len, is_unicode, nls_codepage);
3434 goto qreparse_out;
3435 } else if (reparse_buf->ReparseTag !=
3436 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3437 rc = -EOPNOTSUPP;
3438 goto qreparse_out;
3439 }
3440
3441 /* Reparse tag is NTFS symlink */
3442 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3443 reparse_buf->PathBuffer;
3444 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3445 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003446 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3447 rc = -EIO;
3448 goto qreparse_out;
3449 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003450 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3451 is_unicode = true;
3452 else
3453 is_unicode = false;
3454
3455 /* BB FIXME investigate remapping reserved chars here */
3456 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3457 nls_codepage);
3458 if (!*symlinkinfo)
3459 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003461 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003463 /*
3464 * Note: On -EAGAIN error only caller can retry on handle based calls
3465 * since file handle passed in no longer valid.
3466 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 return rc;
3468}
3469
Steve Frenchc7f508a2013-10-14 15:27:32 -05003470int
3471CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3472 __u16 fid)
3473{
3474 int rc = 0;
3475 int bytes_returned;
3476 struct smb_com_transaction_compr_ioctl_req *pSMB;
3477 struct smb_com_transaction_ioctl_rsp *pSMBr;
3478
3479 cifs_dbg(FYI, "Set compression for %u\n", fid);
3480 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3481 (void **) &pSMBr);
3482 if (rc)
3483 return rc;
3484
3485 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3486
3487 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003488 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003489 pSMB->MaxParameterCount = 0;
3490 pSMB->MaxDataCount = 0;
3491 pSMB->MaxSetupCount = 4;
3492 pSMB->Reserved = 0;
3493 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003494 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003495 pSMB->DataOffset =
3496 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3497 compression_state) - 4); /* 84 */
3498 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003499 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003500 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003501 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003502 pSMB->IsFsctl = 1; /* FSCTL */
3503 pSMB->IsRootFlag = 0;
3504 pSMB->Fid = fid; /* file handle always le */
3505 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003506 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003507 inc_rfc1001_len(pSMB, 5);
3508
3509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3511 if (rc)
3512 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3513
3514 cifs_buf_release(pSMB);
3515
3516 /*
3517 * Note: On -EAGAIN error only caller can retry on handle based calls
3518 * since file handle passed in no longer valid.
3519 */
3520 return rc;
3521}
3522
3523
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524#ifdef CONFIG_CIFS_POSIX
3525
3526/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003527static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003528 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529{
3530 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003531 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3532 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3533 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003534/*
3535 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3536 ace->e_perm, ace->e_tag, ace->e_id);
3537*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538
3539 return;
3540}
3541
3542/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003543static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3544 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545{
3546 int size = 0;
3547 int i;
3548 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003549 struct cifs_posix_ace *pACE;
3550 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003551 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552
3553 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3554 return -EOPNOTSUPP;
3555
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003556 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 count = le16_to_cpu(cifs_acl->access_entry_count);
3558 pACE = &cifs_acl->ace_array[0];
3559 size = sizeof(struct cifs_posix_acl);
3560 size += sizeof(struct cifs_posix_ace) * count;
3561 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003562 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003563 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3564 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 return -EINVAL;
3566 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003567 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 count = le16_to_cpu(cifs_acl->access_entry_count);
3569 size = sizeof(struct cifs_posix_acl);
3570 size += sizeof(struct cifs_posix_ace) * count;
3571/* skip past access ACEs to get to default ACEs */
3572 pACE = &cifs_acl->ace_array[count];
3573 count = le16_to_cpu(cifs_acl->default_entry_count);
3574 size += sizeof(struct cifs_posix_ace) * count;
3575 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003576 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 return -EINVAL;
3578 } else {
3579 /* illegal type */
3580 return -EINVAL;
3581 }
3582
3583 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003584 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003585 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003586 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 return -ERANGE;
3588 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003589 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3590
Steve Frenchff7feac2005-11-15 16:45:16 -08003591 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003592 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003593 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003594 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 }
3596 }
3597 return size;
3598}
3599
Steve French50c2f752007-07-13 00:33:32 +00003600static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003601 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602{
3603 __u16 rc = 0; /* 0 = ACL converted ok */
3604
Steve Frenchff7feac2005-11-15 16:45:16 -08003605 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3606 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003608 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 /* Probably no need to le convert -1 on any arch but can not hurt */
3610 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003611 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003612 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003613/*
3614 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3615 ace->e_perm, ace->e_tag, ace->e_id);
3616*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 return rc;
3618}
3619
3620/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003621static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3622 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623{
3624 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003625 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003626 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003627 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 int count;
3629 int i;
3630
Steve French790fe572007-07-07 19:25:05 +00003631 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 return 0;
3633
3634 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003635 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3636 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003637 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003638 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3639 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 return 0;
3641 }
3642 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003643 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003644 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003645 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003646 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003647 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003648 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003649 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003650 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 return 0;
3652 }
Steve French50c2f752007-07-13 00:33:32 +00003653 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003654 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003655 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 /* ACE not converted */
3657 break;
3658 }
3659 }
Steve French790fe572007-07-07 19:25:05 +00003660 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3662 rc += sizeof(struct cifs_posix_acl);
3663 /* BB add check to make sure ACL does not overflow SMB */
3664 }
3665 return rc;
3666}
3667
3668int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003669CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003670 const unsigned char *searchName,
3671 char *acl_inf, const int buflen, const int acl_type,
3672 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673{
3674/* SMB_QUERY_POSIX_ACL */
3675 TRANSACTION2_QPI_REQ *pSMB = NULL;
3676 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3677 int rc = 0;
3678 int bytes_returned;
3679 int name_len;
3680 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003681
Joe Perchesf96637b2013-05-04 22:12:25 -05003682 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
3684queryAclRetry:
3685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3686 (void **) &pSMBr);
3687 if (rc)
3688 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003689
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3691 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003692 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3693 searchName, PATH_MAX, nls_codepage,
3694 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 name_len++; /* trailing null */
3696 name_len *= 2;
3697 pSMB->FileName[name_len] = 0;
3698 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003699 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 name_len = strnlen(searchName, PATH_MAX);
3701 name_len++; /* trailing null */
3702 strncpy(pSMB->FileName, searchName, name_len);
3703 }
3704
3705 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3706 pSMB->TotalDataCount = 0;
3707 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003708 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 pSMB->MaxDataCount = cpu_to_le16(4000);
3710 pSMB->MaxSetupCount = 0;
3711 pSMB->Reserved = 0;
3712 pSMB->Flags = 0;
3713 pSMB->Timeout = 0;
3714 pSMB->Reserved2 = 0;
3715 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003716 offsetof(struct smb_com_transaction2_qpi_req,
3717 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 pSMB->DataCount = 0;
3719 pSMB->DataOffset = 0;
3720 pSMB->SetupCount = 1;
3721 pSMB->Reserved3 = 0;
3722 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3723 byte_count = params + 1 /* pad */ ;
3724 pSMB->TotalParameterCount = cpu_to_le16(params);
3725 pSMB->ParameterCount = pSMB->TotalParameterCount;
3726 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3727 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003728 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 pSMB->ByteCount = cpu_to_le16(byte_count);
3730
3731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003733 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003735 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 } else {
3737 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003738
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003741 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 rc = -EIO; /* bad smb */
3743 else {
3744 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3745 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3746 rc = cifs_copy_posix_acl(acl_inf,
3747 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003748 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 }
3750 }
3751 cifs_buf_release(pSMB);
3752 if (rc == -EAGAIN)
3753 goto queryAclRetry;
3754 return rc;
3755}
3756
3757int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003758CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003759 const unsigned char *fileName,
3760 const char *local_acl, const int buflen,
3761 const int acl_type,
3762 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763{
3764 struct smb_com_transaction2_spi_req *pSMB = NULL;
3765 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3766 char *parm_data;
3767 int name_len;
3768 int rc = 0;
3769 int bytes_returned = 0;
3770 __u16 params, byte_count, data_count, param_offset, offset;
3771
Joe Perchesf96637b2013-05-04 22:12:25 -05003772 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773setAclRetry:
3774 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003775 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 if (rc)
3777 return rc;
3778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3779 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003780 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3781 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 name_len++; /* trailing null */
3783 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003784 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 name_len = strnlen(fileName, PATH_MAX);
3786 name_len++; /* trailing null */
3787 strncpy(pSMB->FileName, fileName, name_len);
3788 }
3789 params = 6 + name_len;
3790 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003791 /* BB find max SMB size from sess */
3792 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 pSMB->MaxSetupCount = 0;
3794 pSMB->Reserved = 0;
3795 pSMB->Flags = 0;
3796 pSMB->Timeout = 0;
3797 pSMB->Reserved2 = 0;
3798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003799 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 offset = param_offset + params;
3801 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3802 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3803
3804 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003805 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806
Steve French790fe572007-07-07 19:25:05 +00003807 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 rc = -EOPNOTSUPP;
3809 goto setACLerrorExit;
3810 }
3811 pSMB->DataOffset = cpu_to_le16(offset);
3812 pSMB->SetupCount = 1;
3813 pSMB->Reserved3 = 0;
3814 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3815 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3816 byte_count = 3 /* pad */ + params + data_count;
3817 pSMB->DataCount = cpu_to_le16(data_count);
3818 pSMB->TotalDataCount = pSMB->DataCount;
3819 pSMB->ParameterCount = cpu_to_le16(params);
3820 pSMB->TotalParameterCount = pSMB->ParameterCount;
3821 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003822 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 pSMB->ByteCount = cpu_to_le16(byte_count);
3824 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003825 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003826 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003827 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
3829setACLerrorExit:
3830 cifs_buf_release(pSMB);
3831 if (rc == -EAGAIN)
3832 goto setAclRetry;
3833 return rc;
3834}
3835
Steve Frenchf654bac2005-04-28 22:41:04 -07003836/* BB fix tabs in this function FIXME BB */
3837int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003838CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003839 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003840{
Steve French50c2f752007-07-13 00:33:32 +00003841 int rc = 0;
3842 struct smb_t2_qfi_req *pSMB = NULL;
3843 struct smb_t2_qfi_rsp *pSMBr = NULL;
3844 int bytes_returned;
3845 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003846
Joe Perchesf96637b2013-05-04 22:12:25 -05003847 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003848 if (tcon == NULL)
3849 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003850
3851GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003852 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3853 (void **) &pSMBr);
3854 if (rc)
3855 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003856
Steve Frenchad7a2922008-02-07 23:25:02 +00003857 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003858 pSMB->t2.TotalDataCount = 0;
3859 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3860 /* BB find exact max data count below from sess structure BB */
3861 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3862 pSMB->t2.MaxSetupCount = 0;
3863 pSMB->t2.Reserved = 0;
3864 pSMB->t2.Flags = 0;
3865 pSMB->t2.Timeout = 0;
3866 pSMB->t2.Reserved2 = 0;
3867 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3868 Fid) - 4);
3869 pSMB->t2.DataCount = 0;
3870 pSMB->t2.DataOffset = 0;
3871 pSMB->t2.SetupCount = 1;
3872 pSMB->t2.Reserved3 = 0;
3873 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3874 byte_count = params + 1 /* pad */ ;
3875 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3876 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3877 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3878 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003879 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003880 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003881 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003882
Steve French790fe572007-07-07 19:25:05 +00003883 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3884 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3885 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003886 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003887 } else {
3888 /* decode response */
3889 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003890 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003891 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003892 /* If rc should we check for EOPNOSUPP and
3893 disable the srvino flag? or in caller? */
3894 rc = -EIO; /* bad smb */
3895 else {
3896 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3897 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3898 struct file_chattr_info *pfinfo;
3899 /* BB Do we need a cast or hash here ? */
3900 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003901 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003902 rc = -EIO;
3903 goto GetExtAttrOut;
3904 }
3905 pfinfo = (struct file_chattr_info *)
3906 (data_offset + (char *) &pSMBr->hdr.Protocol);
3907 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003908 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003909 }
3910 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003911GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003912 cifs_buf_release(pSMB);
3913 if (rc == -EAGAIN)
3914 goto GetExtAttrRetry;
3915 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003916}
3917
Steve Frenchf654bac2005-04-28 22:41:04 -07003918#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919
Jeff Layton79df1ba2010-12-06 12:52:08 -05003920#ifdef CONFIG_CIFS_ACL
3921/*
3922 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3923 * all NT TRANSACTS that we init here have total parm and data under about 400
3924 * bytes (to fit in small cifs buffer size), which is the case so far, it
3925 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3926 * returned setup area) and MaxParameterCount (returned parms size) must be set
3927 * by caller
3928 */
3929static int
3930smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003931 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003932 void **ret_buf)
3933{
3934 int rc;
3935 __u32 temp_offset;
3936 struct smb_com_ntransact_req *pSMB;
3937
3938 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3939 (void **)&pSMB);
3940 if (rc)
3941 return rc;
3942 *ret_buf = (void *)pSMB;
3943 pSMB->Reserved = 0;
3944 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3945 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003946 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003947 pSMB->ParameterCount = pSMB->TotalParameterCount;
3948 pSMB->DataCount = pSMB->TotalDataCount;
3949 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3950 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3951 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3952 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3953 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3954 pSMB->SubCommand = cpu_to_le16(sub_command);
3955 return 0;
3956}
3957
3958static int
3959validate_ntransact(char *buf, char **ppparm, char **ppdata,
3960 __u32 *pparmlen, __u32 *pdatalen)
3961{
3962 char *end_of_smb;
3963 __u32 data_count, data_offset, parm_count, parm_offset;
3964 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003965 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003966
3967 *pdatalen = 0;
3968 *pparmlen = 0;
3969
3970 if (buf == NULL)
3971 return -EINVAL;
3972
3973 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3974
Jeff Layton820a8032011-05-04 08:05:26 -04003975 bcc = get_bcc(&pSMBr->hdr);
3976 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003977 (char *)&pSMBr->ByteCount;
3978
3979 data_offset = le32_to_cpu(pSMBr->DataOffset);
3980 data_count = le32_to_cpu(pSMBr->DataCount);
3981 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3982 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3983
3984 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3985 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3986
3987 /* should we also check that parm and data areas do not overlap? */
3988 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003989 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003990 return -EINVAL;
3991 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003992 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003993 return -EINVAL;
3994 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003995 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003996 return -EINVAL;
3997 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003998 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3999 *ppdata, data_count, (data_count + *ppdata),
4000 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05004001 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04004002 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004003 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05004004 return -EINVAL;
4005 }
4006 *pdatalen = data_count;
4007 *pparmlen = parm_count;
4008 return 0;
4009}
4010
Steve French0a4b92c2006-01-12 15:44:21 -08004011/* Get Security Descriptor (by handle) from remote server for a file or dir */
4012int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004013CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00004014 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08004015{
4016 int rc = 0;
4017 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00004018 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08004019 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004020 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08004021
Joe Perchesf96637b2013-05-04 22:12:25 -05004022 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08004023
Steve French630f3f0c2007-10-25 21:17:17 +00004024 *pbuflen = 0;
4025 *acl_inf = NULL;
4026
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00004027 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08004028 8 /* parm len */, tcon, (void **) &pSMB);
4029 if (rc)
4030 return rc;
4031
4032 pSMB->MaxParameterCount = cpu_to_le32(4);
4033 /* BB TEST with big acls that might need to be e.g. larger than 16K */
4034 pSMB->MaxSetupCount = 0;
4035 pSMB->Fid = fid; /* file handle always le */
4036 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
4037 CIFS_ACL_DACL);
4038 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004039 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08004040 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004041 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08004042
Steve Frencha761ac52007-10-18 21:45:27 +00004043 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004044 0, &rsp_iov);
4045 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004046 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08004047 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004048 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08004049 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00004050 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00004051 __u32 parm_len;
4052 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00004053 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00004054 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08004055
4056/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004057 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00004058 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00004059 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08004060 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004061 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08004062
Joe Perchesf96637b2013-05-04 22:12:25 -05004063 cifs_dbg(FYI, "smb %p parm %p data %p\n",
4064 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08004065
4066 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
4067 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00004068 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08004069 goto qsec_out;
4070 }
4071
4072/* BB check that data area is minimum length and as big as acl_len */
4073
Steve Frenchaf6f4612007-10-16 18:40:37 +00004074 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00004075 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004076 cifs_dbg(VFS, "acl length %d does not match %d\n",
4077 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00004078 if (*pbuflen > acl_len)
4079 *pbuflen = acl_len;
4080 }
Steve French0a4b92c2006-01-12 15:44:21 -08004081
Steve French630f3f0c2007-10-25 21:17:17 +00004082 /* check if buffer is big enough for the acl
4083 header followed by the smallest SID */
4084 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
4085 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004086 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00004087 rc = -EINVAL;
4088 *pbuflen = 0;
4089 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02004090 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00004091 if (*acl_inf == NULL) {
4092 *pbuflen = 0;
4093 rc = -ENOMEM;
4094 }
Steve French630f3f0c2007-10-25 21:17:17 +00004095 }
Steve French0a4b92c2006-01-12 15:44:21 -08004096 }
4097qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004098 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08004099 return rc;
4100}
Steve French97837582007-12-31 07:47:21 +00004101
4102int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004103CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004104 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00004105{
4106 __u16 byte_count, param_count, data_count, param_offset, data_offset;
4107 int rc = 0;
4108 int bytes_returned = 0;
4109 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004110 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00004111
4112setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004113 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00004114 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004115 return rc;
Steve French97837582007-12-31 07:47:21 +00004116
4117 pSMB->MaxSetupCount = 0;
4118 pSMB->Reserved = 0;
4119
4120 param_count = 8;
4121 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
4122 data_count = acllen;
4123 data_offset = param_offset + param_count;
4124 byte_count = 3 /* pad */ + param_count;
4125
4126 pSMB->DataCount = cpu_to_le32(data_count);
4127 pSMB->TotalDataCount = pSMB->DataCount;
4128 pSMB->MaxParameterCount = cpu_to_le32(4);
4129 pSMB->MaxDataCount = cpu_to_le32(16384);
4130 pSMB->ParameterCount = cpu_to_le32(param_count);
4131 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4132 pSMB->TotalParameterCount = pSMB->ParameterCount;
4133 pSMB->DataOffset = cpu_to_le32(data_offset);
4134 pSMB->SetupCount = 0;
4135 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4136 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4137
4138 pSMB->Fid = fid; /* file handle always le */
4139 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004140 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004141
4142 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004143 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4144 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004145 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004146 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004147 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004148
4149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4151
Joe Perchesf96637b2013-05-04 22:12:25 -05004152 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4153 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004154 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004155 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004156 cifs_buf_release(pSMB);
4157
4158 if (rc == -EAGAIN)
4159 goto setCifsAclRetry;
4160
4161 return (rc);
4162}
4163
Jeff Layton79df1ba2010-12-06 12:52:08 -05004164#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004165
Steve French6b8edfe2005-08-23 20:26:03 -07004166/* Legacy Query Path Information call for lookup to old servers such
4167 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004168int
4169SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4170 const char *search_name, FILE_ALL_INFO *data,
4171 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004172{
Steve Frenchad7a2922008-02-07 23:25:02 +00004173 QUERY_INFORMATION_REQ *pSMB;
4174 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004175 int rc = 0;
4176 int bytes_returned;
4177 int name_len;
4178
Joe Perchesf96637b2013-05-04 22:12:25 -05004179 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004180QInfRetry:
4181 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004182 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004183 if (rc)
4184 return rc;
4185
4186 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4187 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004188 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004189 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004190 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004191 name_len++; /* trailing null */
4192 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004193 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004194 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004195 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004196 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004197 }
4198 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004199 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004200 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004201 pSMB->ByteCount = cpu_to_le16(name_len);
4202
4203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004205 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004206 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004207 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004208 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004209 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004210
4211 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004212 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004213 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004214 ts.tv_nsec = 0;
4215 ts.tv_sec = time;
4216 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004217 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4218 data->LastWriteTime = data->ChangeTime;
4219 data->LastAccessTime = 0;
4220 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004221 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004222 data->EndOfFile = data->AllocationSize;
4223 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004224 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004225 } else
4226 rc = -EIO; /* bad buffer passed in */
4227
4228 cifs_buf_release(pSMB);
4229
4230 if (rc == -EAGAIN)
4231 goto QInfRetry;
4232
4233 return rc;
4234}
4235
Jeff Laytonbcd53572010-02-12 07:44:16 -05004236int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004237CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004238 u16 netfid, FILE_ALL_INFO *pFindData)
4239{
4240 struct smb_t2_qfi_req *pSMB = NULL;
4241 struct smb_t2_qfi_rsp *pSMBr = NULL;
4242 int rc = 0;
4243 int bytes_returned;
4244 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004245
Jeff Laytonbcd53572010-02-12 07:44:16 -05004246QFileInfoRetry:
4247 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4248 (void **) &pSMBr);
4249 if (rc)
4250 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004251
Jeff Laytonbcd53572010-02-12 07:44:16 -05004252 params = 2 /* level */ + 2 /* fid */;
4253 pSMB->t2.TotalDataCount = 0;
4254 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4255 /* BB find exact max data count below from sess structure BB */
4256 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4257 pSMB->t2.MaxSetupCount = 0;
4258 pSMB->t2.Reserved = 0;
4259 pSMB->t2.Flags = 0;
4260 pSMB->t2.Timeout = 0;
4261 pSMB->t2.Reserved2 = 0;
4262 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4263 Fid) - 4);
4264 pSMB->t2.DataCount = 0;
4265 pSMB->t2.DataOffset = 0;
4266 pSMB->t2.SetupCount = 1;
4267 pSMB->t2.Reserved3 = 0;
4268 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4269 byte_count = params + 1 /* pad */ ;
4270 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4271 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4272 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4273 pSMB->Pad = 0;
4274 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004275 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004276 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004277
4278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4280 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004281 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004282 } else { /* decode response */
4283 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4284
4285 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4286 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004287 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004288 rc = -EIO; /* bad smb */
4289 else if (pFindData) {
4290 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4291 memcpy((char *) pFindData,
4292 (char *) &pSMBr->hdr.Protocol +
4293 data_offset, sizeof(FILE_ALL_INFO));
4294 } else
4295 rc = -ENOMEM;
4296 }
4297 cifs_buf_release(pSMB);
4298 if (rc == -EAGAIN)
4299 goto QFileInfoRetry;
4300
4301 return rc;
4302}
Steve French6b8edfe2005-08-23 20:26:03 -07004303
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004305CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004306 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004307 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004308 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004310 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 TRANSACTION2_QPI_REQ *pSMB = NULL;
4312 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4313 int rc = 0;
4314 int bytes_returned;
4315 int name_len;
4316 __u16 params, byte_count;
4317
Joe Perchesf96637b2013-05-04 22:12:25 -05004318 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319QPathInfoRetry:
4320 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4321 (void **) &pSMBr);
4322 if (rc)
4323 return rc;
4324
4325 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4326 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004327 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004328 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 name_len++; /* trailing null */
4330 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004331 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004332 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004334 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 }
4336
Steve French50c2f752007-07-13 00:33:32 +00004337 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 pSMB->TotalDataCount = 0;
4339 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004340 /* BB find exact max SMB PDU from sess structure BB */
4341 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 pSMB->MaxSetupCount = 0;
4343 pSMB->Reserved = 0;
4344 pSMB->Flags = 0;
4345 pSMB->Timeout = 0;
4346 pSMB->Reserved2 = 0;
4347 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004348 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 pSMB->DataCount = 0;
4350 pSMB->DataOffset = 0;
4351 pSMB->SetupCount = 1;
4352 pSMB->Reserved3 = 0;
4353 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4354 byte_count = params + 1 /* pad */ ;
4355 pSMB->TotalParameterCount = cpu_to_le16(params);
4356 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004357 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004358 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4359 else
4360 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004362 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 pSMB->ByteCount = cpu_to_le16(byte_count);
4364
4365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4366 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4367 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004368 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 } else { /* decode response */
4370 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4371
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004372 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4373 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004374 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004376 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004377 rc = -EIO; /* 24 or 26 expected but we do not read
4378 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004379 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004380 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004382
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004383 /*
4384 * On legacy responses we do not read the last field,
4385 * EAsize, fortunately since it varies by subdialect and
4386 * also note it differs on Set vs Get, ie two bytes or 4
4387 * bytes depending but we don't care here.
4388 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004389 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004390 size = sizeof(FILE_INFO_STANDARD);
4391 else
4392 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004393 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004394 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 } else
4396 rc = -ENOMEM;
4397 }
4398 cifs_buf_release(pSMB);
4399 if (rc == -EAGAIN)
4400 goto QPathInfoRetry;
4401
4402 return rc;
4403}
4404
4405int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004406CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004407 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4408{
4409 struct smb_t2_qfi_req *pSMB = NULL;
4410 struct smb_t2_qfi_rsp *pSMBr = NULL;
4411 int rc = 0;
4412 int bytes_returned;
4413 __u16 params, byte_count;
4414
4415UnixQFileInfoRetry:
4416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4417 (void **) &pSMBr);
4418 if (rc)
4419 return rc;
4420
4421 params = 2 /* level */ + 2 /* fid */;
4422 pSMB->t2.TotalDataCount = 0;
4423 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4424 /* BB find exact max data count below from sess structure BB */
4425 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4426 pSMB->t2.MaxSetupCount = 0;
4427 pSMB->t2.Reserved = 0;
4428 pSMB->t2.Flags = 0;
4429 pSMB->t2.Timeout = 0;
4430 pSMB->t2.Reserved2 = 0;
4431 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4432 Fid) - 4);
4433 pSMB->t2.DataCount = 0;
4434 pSMB->t2.DataOffset = 0;
4435 pSMB->t2.SetupCount = 1;
4436 pSMB->t2.Reserved3 = 0;
4437 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4438 byte_count = params + 1 /* pad */ ;
4439 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4440 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4441 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4442 pSMB->Pad = 0;
4443 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004444 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004445 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004446
4447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4449 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004450 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004451 } else { /* decode response */
4452 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4453
Jeff Layton820a8032011-05-04 08:05:26 -04004454 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004455 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 -05004456 rc = -EIO; /* bad smb */
4457 } else {
4458 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4459 memcpy((char *) pFindData,
4460 (char *) &pSMBr->hdr.Protocol +
4461 data_offset,
4462 sizeof(FILE_UNIX_BASIC_INFO));
4463 }
4464 }
4465
4466 cifs_buf_release(pSMB);
4467 if (rc == -EAGAIN)
4468 goto UnixQFileInfoRetry;
4469
4470 return rc;
4471}
4472
4473int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004474CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004476 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004477 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478{
4479/* SMB_QUERY_FILE_UNIX_BASIC */
4480 TRANSACTION2_QPI_REQ *pSMB = NULL;
4481 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4482 int rc = 0;
4483 int bytes_returned = 0;
4484 int name_len;
4485 __u16 params, byte_count;
4486
Joe Perchesf96637b2013-05-04 22:12:25 -05004487 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488UnixQPathInfoRetry:
4489 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4490 (void **) &pSMBr);
4491 if (rc)
4492 return rc;
4493
4494 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4495 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004496 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4497 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 name_len++; /* trailing null */
4499 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004500 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 name_len = strnlen(searchName, PATH_MAX);
4502 name_len++; /* trailing null */
4503 strncpy(pSMB->FileName, searchName, name_len);
4504 }
4505
Steve French50c2f752007-07-13 00:33:32 +00004506 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 pSMB->TotalDataCount = 0;
4508 pSMB->MaxParameterCount = cpu_to_le16(2);
4509 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004510 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 pSMB->MaxSetupCount = 0;
4512 pSMB->Reserved = 0;
4513 pSMB->Flags = 0;
4514 pSMB->Timeout = 0;
4515 pSMB->Reserved2 = 0;
4516 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004517 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 pSMB->DataCount = 0;
4519 pSMB->DataOffset = 0;
4520 pSMB->SetupCount = 1;
4521 pSMB->Reserved3 = 0;
4522 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4523 byte_count = params + 1 /* pad */ ;
4524 pSMB->TotalParameterCount = cpu_to_le16(params);
4525 pSMB->ParameterCount = pSMB->TotalParameterCount;
4526 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4527 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004528 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 pSMB->ByteCount = cpu_to_le16(byte_count);
4530
4531 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4532 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4533 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004534 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 } else { /* decode response */
4536 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4537
Jeff Layton820a8032011-05-04 08:05:26 -04004538 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004539 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 -07004540 rc = -EIO; /* bad smb */
4541 } else {
4542 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4543 memcpy((char *) pFindData,
4544 (char *) &pSMBr->hdr.Protocol +
4545 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004546 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 }
4548 }
4549 cifs_buf_release(pSMB);
4550 if (rc == -EAGAIN)
4551 goto UnixQPathInfoRetry;
4552
4553 return rc;
4554}
4555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556/* xid, tcon, searchName and codepage are input parms, rest are returned */
4557int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004558CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004559 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004560 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004561 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562{
4563/* level 257 SMB_ */
4564 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4565 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004566 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 int rc = 0;
4568 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004569 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004571 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572
Joe Perchesf96637b2013-05-04 22:12:25 -05004573 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
4575findFirstRetry:
4576 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4577 (void **) &pSMBr);
4578 if (rc)
4579 return rc;
4580
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004581 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004582 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4585 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004586 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4587 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004588 /* We can not add the asterik earlier in case
4589 it got remapped to 0xF03A as if it were part of the
4590 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004592 if (msearch) {
4593 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4594 pSMB->FileName[name_len+1] = 0;
4595 pSMB->FileName[name_len+2] = '*';
4596 pSMB->FileName[name_len+3] = 0;
4597 name_len += 4; /* now the trailing null */
4598 /* null terminate just in case */
4599 pSMB->FileName[name_len] = 0;
4600 pSMB->FileName[name_len+1] = 0;
4601 name_len += 2;
4602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 } else { /* BB add check for overrun of SMB buf BB */
4604 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004606 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 free buffer exit; BB */
4608 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004609 if (msearch) {
4610 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4611 pSMB->FileName[name_len+1] = '*';
4612 pSMB->FileName[name_len+2] = 0;
4613 name_len += 3;
4614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 }
4616
4617 params = 12 + name_len /* includes null */ ;
4618 pSMB->TotalDataCount = 0; /* no EAs */
4619 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004620 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 pSMB->MaxSetupCount = 0;
4622 pSMB->Reserved = 0;
4623 pSMB->Flags = 0;
4624 pSMB->Timeout = 0;
4625 pSMB->Reserved2 = 0;
4626 byte_count = params + 1 /* pad */ ;
4627 pSMB->TotalParameterCount = cpu_to_le16(params);
4628 pSMB->ParameterCount = pSMB->TotalParameterCount;
4629 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004630 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4631 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 pSMB->DataCount = 0;
4633 pSMB->DataOffset = 0;
4634 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4635 pSMB->Reserved3 = 0;
4636 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4637 pSMB->SearchAttributes =
4638 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4639 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004640 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004641 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4643
4644 /* BB what should we set StorageType to? Does it matter? BB */
4645 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004646 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 pSMB->ByteCount = cpu_to_le16(byte_count);
4648
4649 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4650 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004651 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652
Steve French88274812006-03-09 22:21:45 +00004653 if (rc) {/* BB add logic to retry regular search if Unix search
4654 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004656 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004657
Steve French88274812006-03-09 22:21:45 +00004658 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659
4660 /* BB eventually could optimize out free and realloc of buf */
4661 /* for this case */
4662 if (rc == -EAGAIN)
4663 goto findFirstRetry;
4664 } else { /* decode response */
4665 /* BB remember to free buffer if error BB */
4666 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004667 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004668 unsigned int lnoff;
4669
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004671 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 else
Steve French4b18f2a2008-04-29 00:06:05 +00004673 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674
4675 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004676 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004677 psrch_inf->srch_entries_start =
4678 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4681 le16_to_cpu(pSMBr->t2.ParameterOffset));
4682
Steve French790fe572007-07-07 19:25:05 +00004683 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004684 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 else
Steve French4b18f2a2008-04-29 00:06:05 +00004686 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687
Steve French50c2f752007-07-13 00:33:32 +00004688 psrch_inf->entries_in_buffer =
4689 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004690 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004692 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004693 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004694 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004695 psrch_inf->last_entry = NULL;
4696 return rc;
4697 }
4698
Steve French0752f152008-10-07 20:03:33 +00004699 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004700 lnoff;
4701
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004702 if (pnetfid)
4703 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 } else {
4705 cifs_buf_release(pSMB);
4706 }
4707 }
4708
4709 return rc;
4710}
4711
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004712int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4713 __u16 searchHandle, __u16 search_flags,
4714 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715{
4716 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4717 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004718 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 char *response_data;
4720 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004721 int bytes_returned;
4722 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 __u16 params, byte_count;
4724
Joe Perchesf96637b2013-05-04 22:12:25 -05004725 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726
Steve French4b18f2a2008-04-29 00:06:05 +00004727 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 return -ENOENT;
4729
4730 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4731 (void **) &pSMBr);
4732 if (rc)
4733 return rc;
4734
Steve French50c2f752007-07-13 00:33:32 +00004735 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 byte_count = 0;
4737 pSMB->TotalDataCount = 0; /* no EAs */
4738 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004739 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 pSMB->MaxSetupCount = 0;
4741 pSMB->Reserved = 0;
4742 pSMB->Flags = 0;
4743 pSMB->Timeout = 0;
4744 pSMB->Reserved2 = 0;
4745 pSMB->ParameterOffset = cpu_to_le16(
4746 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4747 pSMB->DataCount = 0;
4748 pSMB->DataOffset = 0;
4749 pSMB->SetupCount = 1;
4750 pSMB->Reserved3 = 0;
4751 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4752 pSMB->SearchHandle = searchHandle; /* always kept as le */
4753 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004754 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4756 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004757 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
4759 name_len = psrch_inf->resume_name_len;
4760 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004761 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4763 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004764 /* 14 byte parm len above enough for 2 byte null terminator */
4765 pSMB->ResumeFileName[name_len] = 0;
4766 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 } else {
4768 rc = -EINVAL;
4769 goto FNext2_err_exit;
4770 }
4771 byte_count = params + 1 /* pad */ ;
4772 pSMB->TotalParameterCount = cpu_to_le16(params);
4773 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004774 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004776
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4778 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004779 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 if (rc) {
4781 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004782 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004783 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004784 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004786 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 } else { /* decode response */
4788 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004789
Steve French790fe572007-07-07 19:25:05 +00004790 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004791 unsigned int lnoff;
4792
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 /* BB fixme add lock for file (srch_info) struct here */
4794 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004795 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 else
Steve French4b18f2a2008-04-29 00:06:05 +00004797 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 response_data = (char *) &pSMBr->hdr.Protocol +
4799 le16_to_cpu(pSMBr->t2.ParameterOffset);
4800 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4801 response_data = (char *)&pSMBr->hdr.Protocol +
4802 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004803 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004804 cifs_small_buf_release(
4805 psrch_inf->ntwrk_buf_start);
4806 else
4807 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 psrch_inf->srch_entries_start = response_data;
4809 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004810 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004811 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004812 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 else
Steve French4b18f2a2008-04-29 00:06:05 +00004814 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004815 psrch_inf->entries_in_buffer =
4816 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 psrch_inf->index_of_last_entry +=
4818 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004819 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004820 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004821 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004822 psrch_inf->last_entry = NULL;
4823 return rc;
4824 } else
4825 psrch_inf->last_entry =
4826 psrch_inf->srch_entries_start + lnoff;
4827
Joe Perchesf96637b2013-05-04 22:12:25 -05004828/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4829 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
4831 /* BB fixme add unlock here */
4832 }
4833
4834 }
4835
4836 /* BB On error, should we leave previous search buf (and count and
4837 last entry fields) intact or free the previous one? */
4838
4839 /* Note: On -EAGAIN error only caller can retry on handle based calls
4840 since file handle passed in no longer valid */
4841FNext2_err_exit:
4842 if (rc != 0)
4843 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 return rc;
4845}
4846
4847int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004848CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004849 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850{
4851 int rc = 0;
4852 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853
Joe Perchesf96637b2013-05-04 22:12:25 -05004854 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4856
4857 /* no sense returning error if session restarted
4858 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004859 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 return 0;
4861 if (rc)
4862 return rc;
4863
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 pSMB->FileID = searchHandle;
4865 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004866 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004867 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004868 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004869 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004870
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004871 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872
4873 /* Since session is dead, search handle closed on server already */
4874 if (rc == -EAGAIN)
4875 rc = 0;
4876
4877 return rc;
4878}
4879
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004881CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004882 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004883 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884{
4885 int rc = 0;
4886 TRANSACTION2_QPI_REQ *pSMB = NULL;
4887 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4888 int name_len, bytes_returned;
4889 __u16 params, byte_count;
4890
Joe Perchesf96637b2013-05-04 22:12:25 -05004891 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004892 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004893 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894
4895GetInodeNumberRetry:
4896 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004897 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 if (rc)
4899 return rc;
4900
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4902 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004903 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004904 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004905 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 name_len++; /* trailing null */
4907 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004908 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004909 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004911 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 }
4913
4914 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4915 pSMB->TotalDataCount = 0;
4916 pSMB->MaxParameterCount = cpu_to_le16(2);
4917 /* BB find exact max data count below from sess structure BB */
4918 pSMB->MaxDataCount = cpu_to_le16(4000);
4919 pSMB->MaxSetupCount = 0;
4920 pSMB->Reserved = 0;
4921 pSMB->Flags = 0;
4922 pSMB->Timeout = 0;
4923 pSMB->Reserved2 = 0;
4924 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004925 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 pSMB->DataCount = 0;
4927 pSMB->DataOffset = 0;
4928 pSMB->SetupCount = 1;
4929 pSMB->Reserved3 = 0;
4930 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4931 byte_count = params + 1 /* pad */ ;
4932 pSMB->TotalParameterCount = cpu_to_le16(params);
4933 pSMB->ParameterCount = pSMB->TotalParameterCount;
4934 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4935 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004936 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 pSMB->ByteCount = cpu_to_le16(byte_count);
4938
4939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4941 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004942 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 } else {
4944 /* decode response */
4945 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004947 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 /* If rc should we check for EOPNOSUPP and
4949 disable the srvino flag? or in caller? */
4950 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004951 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4953 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004954 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004956 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004957 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 rc = -EIO;
4959 goto GetInodeNumOut;
4960 }
4961 pfinfo = (struct file_internal_info *)
4962 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004963 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 }
4965 }
4966GetInodeNumOut:
4967 cifs_buf_release(pSMB);
4968 if (rc == -EAGAIN)
4969 goto GetInodeNumberRetry;
4970 return rc;
4971}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972
4973int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004974CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004975 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004976 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004977 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978{
4979/* TRANS2_GET_DFS_REFERRAL */
4980 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4981 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 int rc = 0;
4983 int bytes_returned;
4984 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004986 *num_of_nodes = 0;
4987 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988
Joe Perchesf96637b2013-05-04 22:12:25 -05004989 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004990 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004992
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004994 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 (void **) &pSMBr);
4996 if (rc)
4997 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004998
4999 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07005000 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04005001 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01005002 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00005004 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00005006 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
5009 if (ses->capabilities & CAP_UNICODE) {
5010 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
5011 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005012 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04005013 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06005014 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 name_len++; /* trailing null */
5016 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005017 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04005018 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04005020 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 }
5022
Dan Carpenter65c3b202015-04-30 17:30:24 +03005023 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04005024 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00005025
Steve French50c2f752007-07-13 00:33:32 +00005026 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00005027
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 params = 2 /* level */ + name_len /*includes null */ ;
5029 pSMB->TotalDataCount = 0;
5030 pSMB->DataCount = 0;
5031 pSMB->DataOffset = 0;
5032 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00005033 /* BB find exact max SMB PDU from sess structure BB */
5034 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035 pSMB->MaxSetupCount = 0;
5036 pSMB->Reserved = 0;
5037 pSMB->Flags = 0;
5038 pSMB->Timeout = 0;
5039 pSMB->Reserved2 = 0;
5040 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005041 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 pSMB->SetupCount = 1;
5043 pSMB->Reserved3 = 0;
5044 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
5045 byte_count = params + 3 /* pad */ ;
5046 pSMB->ParameterCount = cpu_to_le16(params);
5047 pSMB->TotalParameterCount = pSMB->ParameterCount;
5048 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005049 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 pSMB->ByteCount = cpu_to_le16(byte_count);
5051
5052 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
5053 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5054 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005055 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005056 goto GetDFSRefExit;
5057 }
5058 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005060 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04005061 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005062 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04005063 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 }
Igor Mammedovfec45852008-05-16 13:06:30 +04005065
Joe Perchesf96637b2013-05-04 22:12:25 -05005066 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
5067 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04005068
5069 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01005070 rc = parse_dfs_referrals(&pSMBr->dfs_data,
5071 le16_to_cpu(pSMBr->t2.DataCount),
5072 num_of_nodes, target_nodes, nls_codepage,
5073 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06005074 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04005075
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00005077 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078
5079 if (rc == -EAGAIN)
5080 goto getDFSRetry;
5081
5082 return rc;
5083}
5084
Steve French20962432005-09-21 22:05:57 -07005085/* Query File System Info such as free space to old servers such as Win 9x */
5086int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005087SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5088 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005089{
5090/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5091 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5092 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5093 FILE_SYSTEM_ALLOC_INFO *response_data;
5094 int rc = 0;
5095 int bytes_returned = 0;
5096 __u16 params, byte_count;
5097
Joe Perchesf96637b2013-05-04 22:12:25 -05005098 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005099oldQFSInfoRetry:
5100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5101 (void **) &pSMBr);
5102 if (rc)
5103 return rc;
Steve French20962432005-09-21 22:05:57 -07005104
5105 params = 2; /* level */
5106 pSMB->TotalDataCount = 0;
5107 pSMB->MaxParameterCount = cpu_to_le16(2);
5108 pSMB->MaxDataCount = cpu_to_le16(1000);
5109 pSMB->MaxSetupCount = 0;
5110 pSMB->Reserved = 0;
5111 pSMB->Flags = 0;
5112 pSMB->Timeout = 0;
5113 pSMB->Reserved2 = 0;
5114 byte_count = params + 1 /* pad */ ;
5115 pSMB->TotalParameterCount = cpu_to_le16(params);
5116 pSMB->ParameterCount = pSMB->TotalParameterCount;
5117 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5118 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5119 pSMB->DataCount = 0;
5120 pSMB->DataOffset = 0;
5121 pSMB->SetupCount = 1;
5122 pSMB->Reserved3 = 0;
5123 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5124 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005125 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005126 pSMB->ByteCount = cpu_to_le16(byte_count);
5127
5128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5130 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005131 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005132 } else { /* decode response */
5133 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5134
Jeff Layton820a8032011-05-04 08:05:26 -04005135 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005136 rc = -EIO; /* bad smb */
5137 else {
5138 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005139 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005140 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005141
Steve French50c2f752007-07-13 00:33:32 +00005142 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005143 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5144 FSData->f_bsize =
5145 le16_to_cpu(response_data->BytesPerSector) *
5146 le32_to_cpu(response_data->
5147 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005148 /*
5149 * much prefer larger but if server doesn't report
5150 * a valid size than 4K is a reasonable minimum
5151 */
5152 if (FSData->f_bsize < 512)
5153 FSData->f_bsize = 4096;
5154
Steve French20962432005-09-21 22:05:57 -07005155 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005156 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005157 FSData->f_bfree = FSData->f_bavail =
5158 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005159 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5160 (unsigned long long)FSData->f_blocks,
5161 (unsigned long long)FSData->f_bfree,
5162 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005163 }
5164 }
5165 cifs_buf_release(pSMB);
5166
5167 if (rc == -EAGAIN)
5168 goto oldQFSInfoRetry;
5169
5170 return rc;
5171}
5172
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005174CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5175 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176{
5177/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5178 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5179 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5180 FILE_SYSTEM_INFO *response_data;
5181 int rc = 0;
5182 int bytes_returned = 0;
5183 __u16 params, byte_count;
5184
Joe Perchesf96637b2013-05-04 22:12:25 -05005185 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186QFSInfoRetry:
5187 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5188 (void **) &pSMBr);
5189 if (rc)
5190 return rc;
5191
5192 params = 2; /* level */
5193 pSMB->TotalDataCount = 0;
5194 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005195 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 pSMB->MaxSetupCount = 0;
5197 pSMB->Reserved = 0;
5198 pSMB->Flags = 0;
5199 pSMB->Timeout = 0;
5200 pSMB->Reserved2 = 0;
5201 byte_count = params + 1 /* pad */ ;
5202 pSMB->TotalParameterCount = cpu_to_le16(params);
5203 pSMB->ParameterCount = pSMB->TotalParameterCount;
5204 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005205 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 pSMB->DataCount = 0;
5207 pSMB->DataOffset = 0;
5208 pSMB->SetupCount = 1;
5209 pSMB->Reserved3 = 0;
5210 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5211 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005212 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 pSMB->ByteCount = cpu_to_le16(byte_count);
5214
5215 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5216 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5217 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005218 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005220 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221
Jeff Layton820a8032011-05-04 08:05:26 -04005222 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 rc = -EIO; /* bad smb */
5224 else {
5225 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
5227 response_data =
5228 (FILE_SYSTEM_INFO
5229 *) (((char *) &pSMBr->hdr.Protocol) +
5230 data_offset);
5231 FSData->f_bsize =
5232 le32_to_cpu(response_data->BytesPerSector) *
5233 le32_to_cpu(response_data->
5234 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005235 /*
5236 * much prefer larger but if server doesn't report
5237 * a valid size than 4K is a reasonable minimum
5238 */
5239 if (FSData->f_bsize < 512)
5240 FSData->f_bsize = 4096;
5241
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 FSData->f_blocks =
5243 le64_to_cpu(response_data->TotalAllocationUnits);
5244 FSData->f_bfree = FSData->f_bavail =
5245 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005246 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5247 (unsigned long long)FSData->f_blocks,
5248 (unsigned long long)FSData->f_bfree,
5249 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 }
5251 }
5252 cifs_buf_release(pSMB);
5253
5254 if (rc == -EAGAIN)
5255 goto QFSInfoRetry;
5256
5257 return rc;
5258}
5259
5260int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005261CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262{
5263/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5264 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5265 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5266 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5267 int rc = 0;
5268 int bytes_returned = 0;
5269 __u16 params, byte_count;
5270
Joe Perchesf96637b2013-05-04 22:12:25 -05005271 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272QFSAttributeRetry:
5273 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5274 (void **) &pSMBr);
5275 if (rc)
5276 return rc;
5277
5278 params = 2; /* level */
5279 pSMB->TotalDataCount = 0;
5280 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005281 /* BB find exact max SMB PDU from sess structure BB */
5282 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 pSMB->MaxSetupCount = 0;
5284 pSMB->Reserved = 0;
5285 pSMB->Flags = 0;
5286 pSMB->Timeout = 0;
5287 pSMB->Reserved2 = 0;
5288 byte_count = params + 1 /* pad */ ;
5289 pSMB->TotalParameterCount = cpu_to_le16(params);
5290 pSMB->ParameterCount = pSMB->TotalParameterCount;
5291 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005292 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 pSMB->DataCount = 0;
5294 pSMB->DataOffset = 0;
5295 pSMB->SetupCount = 1;
5296 pSMB->Reserved3 = 0;
5297 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5298 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005299 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 pSMB->ByteCount = cpu_to_le16(byte_count);
5301
5302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5304 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005305 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 } else { /* decode response */
5307 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5308
Jeff Layton820a8032011-05-04 08:05:26 -04005309 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005310 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 rc = -EIO; /* bad smb */
5312 } else {
5313 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5314 response_data =
5315 (FILE_SYSTEM_ATTRIBUTE_INFO
5316 *) (((char *) &pSMBr->hdr.Protocol) +
5317 data_offset);
5318 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005319 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 }
5321 }
5322 cifs_buf_release(pSMB);
5323
5324 if (rc == -EAGAIN)
5325 goto QFSAttributeRetry;
5326
5327 return rc;
5328}
5329
5330int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005331CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332{
5333/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5334 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5335 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5336 FILE_SYSTEM_DEVICE_INFO *response_data;
5337 int rc = 0;
5338 int bytes_returned = 0;
5339 __u16 params, byte_count;
5340
Joe Perchesf96637b2013-05-04 22:12:25 -05005341 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342QFSDeviceRetry:
5343 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5344 (void **) &pSMBr);
5345 if (rc)
5346 return rc;
5347
5348 params = 2; /* level */
5349 pSMB->TotalDataCount = 0;
5350 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005351 /* BB find exact max SMB PDU from sess structure BB */
5352 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 pSMB->MaxSetupCount = 0;
5354 pSMB->Reserved = 0;
5355 pSMB->Flags = 0;
5356 pSMB->Timeout = 0;
5357 pSMB->Reserved2 = 0;
5358 byte_count = params + 1 /* pad */ ;
5359 pSMB->TotalParameterCount = cpu_to_le16(params);
5360 pSMB->ParameterCount = pSMB->TotalParameterCount;
5361 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005362 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363
5364 pSMB->DataCount = 0;
5365 pSMB->DataOffset = 0;
5366 pSMB->SetupCount = 1;
5367 pSMB->Reserved3 = 0;
5368 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5369 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005370 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 pSMB->ByteCount = cpu_to_le16(byte_count);
5372
5373 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5374 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5375 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005376 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 } else { /* decode response */
5378 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5379
Jeff Layton820a8032011-05-04 08:05:26 -04005380 if (rc || get_bcc(&pSMBr->hdr) <
5381 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 rc = -EIO; /* bad smb */
5383 else {
5384 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5385 response_data =
Steve French737b7582005-04-28 22:41:06 -07005386 (FILE_SYSTEM_DEVICE_INFO *)
5387 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 data_offset);
5389 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005390 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 }
5392 }
5393 cifs_buf_release(pSMB);
5394
5395 if (rc == -EAGAIN)
5396 goto QFSDeviceRetry;
5397
5398 return rc;
5399}
5400
5401int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005402CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403{
5404/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5405 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5406 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5407 FILE_SYSTEM_UNIX_INFO *response_data;
5408 int rc = 0;
5409 int bytes_returned = 0;
5410 __u16 params, byte_count;
5411
Joe Perchesf96637b2013-05-04 22:12:25 -05005412 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005414 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5415 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 if (rc)
5417 return rc;
5418
5419 params = 2; /* level */
5420 pSMB->TotalDataCount = 0;
5421 pSMB->DataCount = 0;
5422 pSMB->DataOffset = 0;
5423 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005424 /* BB find exact max SMB PDU from sess structure BB */
5425 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 pSMB->MaxSetupCount = 0;
5427 pSMB->Reserved = 0;
5428 pSMB->Flags = 0;
5429 pSMB->Timeout = 0;
5430 pSMB->Reserved2 = 0;
5431 byte_count = params + 1 /* pad */ ;
5432 pSMB->ParameterCount = cpu_to_le16(params);
5433 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005434 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5435 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 pSMB->SetupCount = 1;
5437 pSMB->Reserved3 = 0;
5438 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5439 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005440 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 pSMB->ByteCount = cpu_to_le16(byte_count);
5442
5443 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5444 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5445 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005446 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 } else { /* decode response */
5448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5449
Jeff Layton820a8032011-05-04 08:05:26 -04005450 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 rc = -EIO; /* bad smb */
5452 } else {
5453 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5454 response_data =
5455 (FILE_SYSTEM_UNIX_INFO
5456 *) (((char *) &pSMBr->hdr.Protocol) +
5457 data_offset);
5458 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005459 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 }
5461 }
5462 cifs_buf_release(pSMB);
5463
5464 if (rc == -EAGAIN)
5465 goto QFSUnixRetry;
5466
5467
5468 return rc;
5469}
5470
Jeremy Allisonac670552005-06-22 17:26:35 -07005471int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005472CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005473{
5474/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5475 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5476 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5477 int rc = 0;
5478 int bytes_returned = 0;
5479 __u16 params, param_offset, offset, byte_count;
5480
Joe Perchesf96637b2013-05-04 22:12:25 -05005481 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005482SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005483 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005484 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5485 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005486 if (rc)
5487 return rc;
5488
5489 params = 4; /* 2 bytes zero followed by info level. */
5490 pSMB->MaxSetupCount = 0;
5491 pSMB->Reserved = 0;
5492 pSMB->Flags = 0;
5493 pSMB->Timeout = 0;
5494 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005495 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5496 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005497 offset = param_offset + params;
5498
5499 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005500 /* BB find exact max SMB PDU from sess structure BB */
5501 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005502 pSMB->SetupCount = 1;
5503 pSMB->Reserved3 = 0;
5504 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5505 byte_count = 1 /* pad */ + params + 12;
5506
5507 pSMB->DataCount = cpu_to_le16(12);
5508 pSMB->ParameterCount = cpu_to_le16(params);
5509 pSMB->TotalDataCount = pSMB->DataCount;
5510 pSMB->TotalParameterCount = pSMB->ParameterCount;
5511 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5512 pSMB->DataOffset = cpu_to_le16(offset);
5513
5514 /* Params. */
5515 pSMB->FileNum = 0;
5516 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5517
5518 /* Data. */
5519 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5520 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5521 pSMB->ClientUnixCap = cpu_to_le64(cap);
5522
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005523 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005524 pSMB->ByteCount = cpu_to_le16(byte_count);
5525
5526 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5527 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5528 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005529 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005530 } else { /* decode response */
5531 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005532 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005533 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005534 }
5535 cifs_buf_release(pSMB);
5536
5537 if (rc == -EAGAIN)
5538 goto SETFSUnixRetry;
5539
5540 return rc;
5541}
5542
5543
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544
5545int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005546CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005547 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548{
5549/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5550 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5551 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5552 FILE_SYSTEM_POSIX_INFO *response_data;
5553 int rc = 0;
5554 int bytes_returned = 0;
5555 __u16 params, byte_count;
5556
Joe Perchesf96637b2013-05-04 22:12:25 -05005557 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558QFSPosixRetry:
5559 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5560 (void **) &pSMBr);
5561 if (rc)
5562 return rc;
5563
5564 params = 2; /* level */
5565 pSMB->TotalDataCount = 0;
5566 pSMB->DataCount = 0;
5567 pSMB->DataOffset = 0;
5568 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005569 /* BB find exact max SMB PDU from sess structure BB */
5570 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 pSMB->MaxSetupCount = 0;
5572 pSMB->Reserved = 0;
5573 pSMB->Flags = 0;
5574 pSMB->Timeout = 0;
5575 pSMB->Reserved2 = 0;
5576 byte_count = params + 1 /* pad */ ;
5577 pSMB->ParameterCount = cpu_to_le16(params);
5578 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005579 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5580 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 pSMB->SetupCount = 1;
5582 pSMB->Reserved3 = 0;
5583 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5584 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005585 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 pSMB->ByteCount = cpu_to_le16(byte_count);
5587
5588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5590 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005591 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 } else { /* decode response */
5593 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5594
Jeff Layton820a8032011-05-04 08:05:26 -04005595 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 rc = -EIO; /* bad smb */
5597 } else {
5598 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5599 response_data =
5600 (FILE_SYSTEM_POSIX_INFO
5601 *) (((char *) &pSMBr->hdr.Protocol) +
5602 data_offset);
5603 FSData->f_bsize =
5604 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005605 /*
5606 * much prefer larger but if server doesn't report
5607 * a valid size than 4K is a reasonable minimum
5608 */
5609 if (FSData->f_bsize < 512)
5610 FSData->f_bsize = 4096;
5611
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 FSData->f_blocks =
5613 le64_to_cpu(response_data->TotalBlocks);
5614 FSData->f_bfree =
5615 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005616 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 FSData->f_bavail = FSData->f_bfree;
5618 } else {
5619 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005620 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 }
Steve French790fe572007-07-07 19:25:05 +00005622 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005624 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005625 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005627 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 }
5629 }
5630 cifs_buf_release(pSMB);
5631
5632 if (rc == -EAGAIN)
5633 goto QFSPosixRetry;
5634
5635 return rc;
5636}
5637
5638
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005639/*
5640 * We can not use write of zero bytes trick to set file size due to need for
5641 * large file support. Also note that this SetPathInfo is preferred to
5642 * SetFileInfo based method in next routine which is only needed to work around
5643 * a sharing violation bugin Samba which this routine can run into.
5644 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005646CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005647 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5648 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649{
5650 struct smb_com_transaction2_spi_req *pSMB = NULL;
5651 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5652 struct file_end_of_file_info *parm_data;
5653 int name_len;
5654 int rc = 0;
5655 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005656 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005657
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 __u16 params, byte_count, data_count, param_offset, offset;
5659
Joe Perchesf96637b2013-05-04 22:12:25 -05005660 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661SetEOFRetry:
5662 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5663 (void **) &pSMBr);
5664 if (rc)
5665 return rc;
5666
5667 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5668 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005669 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5670 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 name_len++; /* trailing null */
5672 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005673 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005674 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005676 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 }
5678 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005679 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005681 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 pSMB->MaxSetupCount = 0;
5683 pSMB->Reserved = 0;
5684 pSMB->Flags = 0;
5685 pSMB->Timeout = 0;
5686 pSMB->Reserved2 = 0;
5687 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005688 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005690 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005691 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5692 pSMB->InformationLevel =
5693 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5694 else
5695 pSMB->InformationLevel =
5696 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5697 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5699 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005700 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701 else
5702 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005703 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 }
5705
5706 parm_data =
5707 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5708 offset);
5709 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5710 pSMB->DataOffset = cpu_to_le16(offset);
5711 pSMB->SetupCount = 1;
5712 pSMB->Reserved3 = 0;
5713 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5714 byte_count = 3 /* pad */ + params + data_count;
5715 pSMB->DataCount = cpu_to_le16(data_count);
5716 pSMB->TotalDataCount = pSMB->DataCount;
5717 pSMB->ParameterCount = cpu_to_le16(params);
5718 pSMB->TotalParameterCount = pSMB->ParameterCount;
5719 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005720 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 parm_data->FileSize = cpu_to_le64(size);
5722 pSMB->ByteCount = cpu_to_le16(byte_count);
5723 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005725 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005726 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727
5728 cifs_buf_release(pSMB);
5729
5730 if (rc == -EAGAIN)
5731 goto SetEOFRetry;
5732
5733 return rc;
5734}
5735
5736int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005737CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5738 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739{
5740 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 struct file_end_of_file_info *parm_data;
5742 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 __u16 params, param_offset, offset, byte_count, count;
5744
Joe Perchesf96637b2013-05-04 22:12:25 -05005745 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5746 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005747 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5748
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 if (rc)
5750 return rc;
5751
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005752 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5753 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005754
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 params = 6;
5756 pSMB->MaxSetupCount = 0;
5757 pSMB->Reserved = 0;
5758 pSMB->Flags = 0;
5759 pSMB->Timeout = 0;
5760 pSMB->Reserved2 = 0;
5761 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5762 offset = param_offset + params;
5763
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 count = sizeof(struct file_end_of_file_info);
5765 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005766 /* BB find exact max SMB PDU from sess structure BB */
5767 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 pSMB->SetupCount = 1;
5769 pSMB->Reserved3 = 0;
5770 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5771 byte_count = 3 /* pad */ + params + count;
5772 pSMB->DataCount = cpu_to_le16(count);
5773 pSMB->ParameterCount = cpu_to_le16(params);
5774 pSMB->TotalDataCount = pSMB->DataCount;
5775 pSMB->TotalParameterCount = pSMB->ParameterCount;
5776 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5777 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005778 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5779 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 pSMB->DataOffset = cpu_to_le16(offset);
5781 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005782 pSMB->Fid = cfile->fid.netfid;
5783 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5785 pSMB->InformationLevel =
5786 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5787 else
5788 pSMB->InformationLevel =
5789 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005790 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5792 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005793 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 else
5795 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005796 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 }
5798 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005799 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005801 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005802 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005804 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5805 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 }
5807
Steve French50c2f752007-07-13 00:33:32 +00005808 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 since file handle passed in no longer valid */
5810
5811 return rc;
5812}
5813
Steve French50c2f752007-07-13 00:33:32 +00005814/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 an open handle, rather than by pathname - this is awkward due to
5816 potential access conflicts on the open, but it is unavoidable for these
5817 old servers since the only other choice is to go from 100 nanosecond DCE
5818 time and resort to the original setpathinfo level which takes the ancient
5819 DOS time format with 2 second granularity */
5820int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005821CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005822 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823{
5824 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 char *data_offset;
5826 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 __u16 params, param_offset, offset, byte_count, count;
5828
Joe Perchesf96637b2013-05-04 22:12:25 -05005829 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005830 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5831
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832 if (rc)
5833 return rc;
5834
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005835 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5836 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005837
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 params = 6;
5839 pSMB->MaxSetupCount = 0;
5840 pSMB->Reserved = 0;
5841 pSMB->Flags = 0;
5842 pSMB->Timeout = 0;
5843 pSMB->Reserved2 = 0;
5844 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5845 offset = param_offset + params;
5846
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005847 data_offset = (char *)pSMB +
5848 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005849
Steve French26f57362007-08-30 22:09:15 +00005850 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005852 /* BB find max SMB PDU from sess */
5853 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 pSMB->SetupCount = 1;
5855 pSMB->Reserved3 = 0;
5856 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5857 byte_count = 3 /* pad */ + params + count;
5858 pSMB->DataCount = cpu_to_le16(count);
5859 pSMB->ParameterCount = cpu_to_le16(params);
5860 pSMB->TotalDataCount = pSMB->DataCount;
5861 pSMB->TotalParameterCount = pSMB->ParameterCount;
5862 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5863 pSMB->DataOffset = cpu_to_le16(offset);
5864 pSMB->Fid = fid;
5865 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5867 else
5868 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5869 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005870 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005872 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005873 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005874 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005875 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005876 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5877 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878
Steve French50c2f752007-07-13 00:33:32 +00005879 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 since file handle passed in no longer valid */
5881
5882 return rc;
5883}
5884
Jeff Layton6d22f092008-09-23 11:48:35 -04005885int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005886CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005887 bool delete_file, __u16 fid, __u32 pid_of_opener)
5888{
5889 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5890 char *data_offset;
5891 int rc = 0;
5892 __u16 params, param_offset, offset, byte_count, count;
5893
Joe Perchesf96637b2013-05-04 22:12:25 -05005894 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005895 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5896
5897 if (rc)
5898 return rc;
5899
5900 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5901 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5902
5903 params = 6;
5904 pSMB->MaxSetupCount = 0;
5905 pSMB->Reserved = 0;
5906 pSMB->Flags = 0;
5907 pSMB->Timeout = 0;
5908 pSMB->Reserved2 = 0;
5909 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5910 offset = param_offset + params;
5911
5912 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5913
5914 count = 1;
5915 pSMB->MaxParameterCount = cpu_to_le16(2);
5916 /* BB find max SMB PDU from sess */
5917 pSMB->MaxDataCount = cpu_to_le16(1000);
5918 pSMB->SetupCount = 1;
5919 pSMB->Reserved3 = 0;
5920 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5921 byte_count = 3 /* pad */ + params + count;
5922 pSMB->DataCount = cpu_to_le16(count);
5923 pSMB->ParameterCount = cpu_to_le16(params);
5924 pSMB->TotalDataCount = pSMB->DataCount;
5925 pSMB->TotalParameterCount = pSMB->ParameterCount;
5926 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5927 pSMB->DataOffset = cpu_to_le16(offset);
5928 pSMB->Fid = fid;
5929 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5930 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005931 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005932 pSMB->ByteCount = cpu_to_le16(byte_count);
5933 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005934 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005935 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005936 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005937 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005938
5939 return rc;
5940}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941
5942int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005943CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005944 const char *fileName, const FILE_BASIC_INFO *data,
5945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946{
5947 TRANSACTION2_SPI_REQ *pSMB = NULL;
5948 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5949 int name_len;
5950 int rc = 0;
5951 int bytes_returned = 0;
5952 char *data_offset;
5953 __u16 params, param_offset, offset, byte_count, count;
5954
Joe Perchesf96637b2013-05-04 22:12:25 -05005955 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956
5957SetTimesRetry:
5958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5959 (void **) &pSMBr);
5960 if (rc)
5961 return rc;
5962
5963 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5964 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005965 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5966 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 name_len++; /* trailing null */
5968 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005969 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 name_len = strnlen(fileName, PATH_MAX);
5971 name_len++; /* trailing null */
5972 strncpy(pSMB->FileName, fileName, name_len);
5973 }
5974
5975 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005976 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005978 /* BB find max SMB PDU from sess structure BB */
5979 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 pSMB->MaxSetupCount = 0;
5981 pSMB->Reserved = 0;
5982 pSMB->Flags = 0;
5983 pSMB->Timeout = 0;
5984 pSMB->Reserved2 = 0;
5985 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005986 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 offset = param_offset + params;
5988 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5989 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5990 pSMB->DataOffset = cpu_to_le16(offset);
5991 pSMB->SetupCount = 1;
5992 pSMB->Reserved3 = 0;
5993 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5994 byte_count = 3 /* pad */ + params + count;
5995
5996 pSMB->DataCount = cpu_to_le16(count);
5997 pSMB->ParameterCount = cpu_to_le16(params);
5998 pSMB->TotalDataCount = pSMB->DataCount;
5999 pSMB->TotalParameterCount = pSMB->ParameterCount;
6000 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
6001 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
6002 else
6003 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
6004 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006005 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00006006 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 pSMB->ByteCount = cpu_to_le16(byte_count);
6008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006010 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006011 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012
6013 cifs_buf_release(pSMB);
6014
6015 if (rc == -EAGAIN)
6016 goto SetTimesRetry;
6017
6018 return rc;
6019}
6020
6021/* Can not be used to set time stamps yet (due to old DOS time format) */
6022/* Can be used to set attributes */
6023#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
6024 handling it anyway and NT4 was what we thought it would be needed for
6025 Do not delete it until we prove whether needed for Win9x though */
6026int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006027CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 __u16 dos_attrs, const struct nls_table *nls_codepage)
6029{
6030 SETATTR_REQ *pSMB = NULL;
6031 SETATTR_RSP *pSMBr = NULL;
6032 int rc = 0;
6033 int bytes_returned;
6034 int name_len;
6035
Joe Perchesf96637b2013-05-04 22:12:25 -05006036 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037
6038SetAttrLgcyRetry:
6039 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
6040 (void **) &pSMBr);
6041 if (rc)
6042 return rc;
6043
6044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6045 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006046 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
6047 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 name_len++; /* trailing null */
6049 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006050 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051 name_len = strnlen(fileName, PATH_MAX);
6052 name_len++; /* trailing null */
6053 strncpy(pSMB->fileName, fileName, name_len);
6054 }
6055 pSMB->attr = cpu_to_le16(dos_attrs);
6056 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006057 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 pSMB->ByteCount = cpu_to_le16(name_len + 1);
6059 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006061 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006062 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063
6064 cifs_buf_release(pSMB);
6065
6066 if (rc == -EAGAIN)
6067 goto SetAttrLgcyRetry;
6068
6069 return rc;
6070}
6071#endif /* temporarily unneeded SetAttr legacy function */
6072
Jeff Layton654cf142009-07-09 20:02:49 -04006073static void
6074cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
6075 const struct cifs_unix_set_info_args *args)
6076{
Eric W. Biederman49418b22013-02-06 00:57:56 -08006077 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04006078 u64 mode = args->mode;
6079
Eric W. Biederman49418b22013-02-06 00:57:56 -08006080 if (uid_valid(args->uid))
6081 uid = from_kuid(&init_user_ns, args->uid);
6082 if (gid_valid(args->gid))
6083 gid = from_kgid(&init_user_ns, args->gid);
6084
Jeff Layton654cf142009-07-09 20:02:49 -04006085 /*
6086 * Samba server ignores set of file size to zero due to bugs in some
6087 * older clients, but we should be precise - we use SetFileSize to
6088 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006089 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04006090 * zero instead of -1 here
6091 */
6092 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
6093 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
6094 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
6095 data_offset->LastAccessTime = cpu_to_le64(args->atime);
6096 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08006097 data_offset->Uid = cpu_to_le64(uid);
6098 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04006099 /* better to leave device as zero when it is */
6100 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
6101 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
6102 data_offset->Permissions = cpu_to_le64(mode);
6103
6104 if (S_ISREG(mode))
6105 data_offset->Type = cpu_to_le32(UNIX_FILE);
6106 else if (S_ISDIR(mode))
6107 data_offset->Type = cpu_to_le32(UNIX_DIR);
6108 else if (S_ISLNK(mode))
6109 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6110 else if (S_ISCHR(mode))
6111 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6112 else if (S_ISBLK(mode))
6113 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6114 else if (S_ISFIFO(mode))
6115 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6116 else if (S_ISSOCK(mode))
6117 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6118}
6119
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006121CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006122 const struct cifs_unix_set_info_args *args,
6123 u16 fid, u32 pid_of_opener)
6124{
6125 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006126 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006127 int rc = 0;
6128 u16 params, param_offset, offset, byte_count, count;
6129
Joe Perchesf96637b2013-05-04 22:12:25 -05006130 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006131 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6132
6133 if (rc)
6134 return rc;
6135
6136 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6137 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6138
6139 params = 6;
6140 pSMB->MaxSetupCount = 0;
6141 pSMB->Reserved = 0;
6142 pSMB->Flags = 0;
6143 pSMB->Timeout = 0;
6144 pSMB->Reserved2 = 0;
6145 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6146 offset = param_offset + params;
6147
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006148 data_offset = (char *)pSMB +
6149 offsetof(struct smb_hdr, Protocol) + offset;
6150
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006151 count = sizeof(FILE_UNIX_BASIC_INFO);
6152
6153 pSMB->MaxParameterCount = cpu_to_le16(2);
6154 /* BB find max SMB PDU from sess */
6155 pSMB->MaxDataCount = cpu_to_le16(1000);
6156 pSMB->SetupCount = 1;
6157 pSMB->Reserved3 = 0;
6158 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6159 byte_count = 3 /* pad */ + params + count;
6160 pSMB->DataCount = cpu_to_le16(count);
6161 pSMB->ParameterCount = cpu_to_le16(params);
6162 pSMB->TotalDataCount = pSMB->DataCount;
6163 pSMB->TotalParameterCount = pSMB->ParameterCount;
6164 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6165 pSMB->DataOffset = cpu_to_le16(offset);
6166 pSMB->Fid = fid;
6167 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6168 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006169 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006170 pSMB->ByteCount = cpu_to_le16(byte_count);
6171
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006172 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006173
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006174 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006175 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006176 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006177 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6178 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006179
6180 /* Note: On -EAGAIN error only caller can retry on handle based calls
6181 since file handle passed in no longer valid */
6182
6183 return rc;
6184}
6185
6186int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006187CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006188 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006189 const struct cifs_unix_set_info_args *args,
6190 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191{
6192 TRANSACTION2_SPI_REQ *pSMB = NULL;
6193 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6194 int name_len;
6195 int rc = 0;
6196 int bytes_returned = 0;
6197 FILE_UNIX_BASIC_INFO *data_offset;
6198 __u16 params, param_offset, offset, count, byte_count;
6199
Joe Perchesf96637b2013-05-04 22:12:25 -05006200 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201setPermsRetry:
6202 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6203 (void **) &pSMBr);
6204 if (rc)
6205 return rc;
6206
6207 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6208 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006209 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006210 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 name_len++; /* trailing null */
6212 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006213 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006214 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006216 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 }
6218
6219 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006220 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006222 /* BB find max SMB PDU from sess structure BB */
6223 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 pSMB->MaxSetupCount = 0;
6225 pSMB->Reserved = 0;
6226 pSMB->Flags = 0;
6227 pSMB->Timeout = 0;
6228 pSMB->Reserved2 = 0;
6229 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006230 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231 offset = param_offset + params;
6232 data_offset =
6233 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6234 offset);
6235 memset(data_offset, 0, count);
6236 pSMB->DataOffset = cpu_to_le16(offset);
6237 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6238 pSMB->SetupCount = 1;
6239 pSMB->Reserved3 = 0;
6240 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6241 byte_count = 3 /* pad */ + params + count;
6242 pSMB->ParameterCount = cpu_to_le16(params);
6243 pSMB->DataCount = cpu_to_le16(count);
6244 pSMB->TotalParameterCount = pSMB->ParameterCount;
6245 pSMB->TotalDataCount = pSMB->DataCount;
6246 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6247 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006248 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006249
Jeff Layton654cf142009-07-09 20:02:49 -04006250 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251
6252 pSMB->ByteCount = cpu_to_le16(byte_count);
6253 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6254 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006255 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006256 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257
Steve French0d817bc2008-05-22 02:02:03 +00006258 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 if (rc == -EAGAIN)
6260 goto setPermsRetry;
6261 return rc;
6262}
6263
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006265/*
6266 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6267 * function used by listxattr and getxattr type calls. When ea_name is set,
6268 * it looks for that attribute name and stuffs that value into the EAData
6269 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6270 * buffer. In both cases, the return value is either the length of the
6271 * resulting data or a negative error code. If EAData is a NULL pointer then
6272 * the data isn't copied to it, but the length is returned.
6273 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006275CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006276 const unsigned char *searchName, const unsigned char *ea_name,
6277 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006278 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279{
6280 /* BB assumes one setup word */
6281 TRANSACTION2_QPI_REQ *pSMB = NULL;
6282 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006283 int remap = cifs_remap(cifs_sb);
6284 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 int rc = 0;
6286 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006287 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006288 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006289 struct fea *temp_fea;
6290 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006291 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006292 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006293 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294
Joe Perchesf96637b2013-05-04 22:12:25 -05006295 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296QAllEAsRetry:
6297 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6298 (void **) &pSMBr);
6299 if (rc)
6300 return rc;
6301
6302 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006303 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006304 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6305 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006306 list_len++; /* trailing null */
6307 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006309 list_len = strnlen(searchName, PATH_MAX);
6310 list_len++; /* trailing null */
6311 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 }
6313
Jeff Layton6e462b92010-02-10 16:18:26 -05006314 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 pSMB->TotalDataCount = 0;
6316 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006317 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006318 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 pSMB->MaxSetupCount = 0;
6320 pSMB->Reserved = 0;
6321 pSMB->Flags = 0;
6322 pSMB->Timeout = 0;
6323 pSMB->Reserved2 = 0;
6324 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006325 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326 pSMB->DataCount = 0;
6327 pSMB->DataOffset = 0;
6328 pSMB->SetupCount = 1;
6329 pSMB->Reserved3 = 0;
6330 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6331 byte_count = params + 1 /* pad */ ;
6332 pSMB->TotalParameterCount = cpu_to_le16(params);
6333 pSMB->ParameterCount = pSMB->TotalParameterCount;
6334 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6335 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006336 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 pSMB->ByteCount = cpu_to_le16(byte_count);
6338
6339 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6340 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6341 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006342 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006343 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006345
6346
6347 /* BB also check enough total bytes returned */
6348 /* BB we need to improve the validity checking
6349 of these trans2 responses */
6350
6351 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006352 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006353 rc = -EIO; /* bad smb */
6354 goto QAllEAsOut;
6355 }
6356
6357 /* check that length of list is not more than bcc */
6358 /* check that each entry does not go beyond length
6359 of list */
6360 /* check that each element of each entry does not
6361 go beyond end of list */
6362 /* validate_trans2_offsets() */
6363 /* BB check if start of smb + data_offset > &bcc+ bcc */
6364
6365 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6366 ea_response_data = (struct fealist *)
6367 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6368
Jeff Layton6e462b92010-02-10 16:18:26 -05006369 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006370 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006371 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006372 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006373 /* didn't find the named attribute */
6374 if (ea_name)
6375 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006376 goto QAllEAsOut;
6377 }
6378
Jeff Layton0cd126b2010-02-10 16:18:26 -05006379 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006380 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006381 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006382 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006383 rc = -EIO;
6384 goto QAllEAsOut;
6385 }
6386
Jeff Laytonf0d38682010-02-10 16:18:26 -05006387 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006388 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006389 temp_fea = ea_response_data->list;
6390 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006391 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006392 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006393 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006394
Jeff Layton6e462b92010-02-10 16:18:26 -05006395 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006396 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006397 /* make sure we can read name_len and value_len */
6398 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006399 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006400 rc = -EIO;
6401 goto QAllEAsOut;
6402 }
6403
6404 name_len = temp_fea->name_len;
6405 value_len = le16_to_cpu(temp_fea->value_len);
6406 list_len -= name_len + 1 + value_len;
6407 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006408 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006409 rc = -EIO;
6410 goto QAllEAsOut;
6411 }
6412
Jeff Layton31c05192010-02-10 16:18:26 -05006413 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006414 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006415 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006416 temp_ptr += name_len + 1;
6417 rc = value_len;
6418 if (buf_size == 0)
6419 goto QAllEAsOut;
6420 if ((size_t)value_len > buf_size) {
6421 rc = -ERANGE;
6422 goto QAllEAsOut;
6423 }
6424 memcpy(EAData, temp_ptr, value_len);
6425 goto QAllEAsOut;
6426 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006427 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006428 /* account for prefix user. and trailing null */
6429 rc += (5 + 1 + name_len);
6430 if (rc < (int) buf_size) {
6431 memcpy(EAData, "user.", 5);
6432 EAData += 5;
6433 memcpy(EAData, temp_ptr, name_len);
6434 EAData += name_len;
6435 /* null terminate name */
6436 *EAData = 0;
6437 ++EAData;
6438 } else if (buf_size == 0) {
6439 /* skip copy - calc size only */
6440 } else {
6441 /* stop before overrun buffer */
6442 rc = -ERANGE;
6443 break;
6444 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006445 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006446 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006447 temp_fea = (struct fea *)temp_ptr;
6448 }
6449
Jeff Layton31c05192010-02-10 16:18:26 -05006450 /* didn't find the named attribute */
6451 if (ea_name)
6452 rc = -ENODATA;
6453
Jeff Laytonf0d38682010-02-10 16:18:26 -05006454QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006455 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 if (rc == -EAGAIN)
6457 goto QAllEAsRetry;
6458
6459 return (ssize_t)rc;
6460}
6461
Linus Torvalds1da177e2005-04-16 15:20:36 -07006462int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006463CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6464 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006465 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006466 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006467{
6468 struct smb_com_transaction2_spi_req *pSMB = NULL;
6469 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6470 struct fealist *parm_data;
6471 int name_len;
6472 int rc = 0;
6473 int bytes_returned = 0;
6474 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006475 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476
Joe Perchesf96637b2013-05-04 22:12:25 -05006477 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478SetEARetry:
6479 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6480 (void **) &pSMBr);
6481 if (rc)
6482 return rc;
6483
6484 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6485 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006486 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6487 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006488 name_len++; /* trailing null */
6489 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006490 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 name_len = strnlen(fileName, PATH_MAX);
6492 name_len++; /* trailing null */
6493 strncpy(pSMB->FileName, fileName, name_len);
6494 }
6495
6496 params = 6 + name_len;
6497
6498 /* done calculating parms using name_len of file name,
6499 now use name_len to calculate length of ea name
6500 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006501 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502 name_len = 0;
6503 else
Steve French50c2f752007-07-13 00:33:32 +00006504 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006505
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006506 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006507 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006508 /* BB find max SMB PDU from sess */
6509 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006510 pSMB->MaxSetupCount = 0;
6511 pSMB->Reserved = 0;
6512 pSMB->Flags = 0;
6513 pSMB->Timeout = 0;
6514 pSMB->Reserved2 = 0;
6515 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006516 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517 offset = param_offset + params;
6518 pSMB->InformationLevel =
6519 cpu_to_le16(SMB_SET_FILE_EA);
6520
Arnd Bergmannade7db92018-02-02 16:48:47 +01006521 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6523 pSMB->DataOffset = cpu_to_le16(offset);
6524 pSMB->SetupCount = 1;
6525 pSMB->Reserved3 = 0;
6526 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6527 byte_count = 3 /* pad */ + params + count;
6528 pSMB->DataCount = cpu_to_le16(count);
6529 parm_data->list_len = cpu_to_le32(count);
6530 parm_data->list[0].EA_flags = 0;
6531 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006532 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006534 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006535 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006536 parm_data->list[0].name[name_len] = 0;
6537 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6538 /* caller ensures that ea_value_len is less than 64K but
6539 we need to ensure that it fits within the smb */
6540
Steve French50c2f752007-07-13 00:33:32 +00006541 /*BB add length check to see if it would fit in
6542 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006543 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6544 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006545 memcpy(parm_data->list[0].name+name_len+1,
6546 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006547
6548 pSMB->TotalDataCount = pSMB->DataCount;
6549 pSMB->ParameterCount = cpu_to_le16(params);
6550 pSMB->TotalParameterCount = pSMB->ParameterCount;
6551 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006552 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006553 pSMB->ByteCount = cpu_to_le16(byte_count);
6554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006556 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006557 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558
6559 cifs_buf_release(pSMB);
6560
6561 if (rc == -EAGAIN)
6562 goto SetEARetry;
6563
6564 return rc;
6565}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566#endif
Steve French0eff0e22011-02-24 05:39:23 +00006567
6568#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6569/*
6570 * Years ago the kernel added a "dnotify" function for Samba server,
6571 * to allow network clients (such as Windows) to display updated
6572 * lists of files in directory listings automatically when
6573 * files are added by one user when another user has the
6574 * same directory open on their desktop. The Linux cifs kernel
6575 * client hooked into the kernel side of this interface for
6576 * the same reason, but ironically when the VFS moved from
6577 * "dnotify" to "inotify" it became harder to plug in Linux
6578 * network file system clients (the most obvious use case
6579 * for notify interfaces is when multiple users can update
6580 * the contents of the same directory - exactly what network
6581 * file systems can do) although the server (Samba) could
6582 * still use it. For the short term we leave the worker
6583 * function ifdeffed out (below) until inotify is fixed
6584 * in the VFS to make it easier to plug in network file
6585 * system clients. If inotify turns out to be permanently
6586 * incompatible for network fs clients, we could instead simply
6587 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6588 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006589int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006590 const int notify_subdirs, const __u16 netfid,
6591 __u32 filter, struct file *pfile, int multishot,
6592 const struct nls_table *nls_codepage)
6593{
6594 int rc = 0;
6595 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6596 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6597 struct dir_notify_req *dnotify_req;
6598 int bytes_returned;
6599
Joe Perchesf96637b2013-05-04 22:12:25 -05006600 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006601 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6602 (void **) &pSMBr);
6603 if (rc)
6604 return rc;
6605
6606 pSMB->TotalParameterCount = 0 ;
6607 pSMB->TotalDataCount = 0;
6608 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006609 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006610 pSMB->MaxSetupCount = 4;
6611 pSMB->Reserved = 0;
6612 pSMB->ParameterOffset = 0;
6613 pSMB->DataCount = 0;
6614 pSMB->DataOffset = 0;
6615 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6616 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6617 pSMB->ParameterCount = pSMB->TotalParameterCount;
6618 if (notify_subdirs)
6619 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6620 pSMB->Reserved2 = 0;
6621 pSMB->CompletionFilter = cpu_to_le32(filter);
6622 pSMB->Fid = netfid; /* file handle always le */
6623 pSMB->ByteCount = 0;
6624
6625 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6626 (struct smb_hdr *)pSMBr, &bytes_returned,
6627 CIFS_ASYNC_OP);
6628 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006629 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006630 } else {
6631 /* Add file to outstanding requests */
6632 /* BB change to kmem cache alloc */
6633 dnotify_req = kmalloc(
6634 sizeof(struct dir_notify_req),
6635 GFP_KERNEL);
6636 if (dnotify_req) {
6637 dnotify_req->Pid = pSMB->hdr.Pid;
6638 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6639 dnotify_req->Mid = pSMB->hdr.Mid;
6640 dnotify_req->Tid = pSMB->hdr.Tid;
6641 dnotify_req->Uid = pSMB->hdr.Uid;
6642 dnotify_req->netfid = netfid;
6643 dnotify_req->pfile = pfile;
6644 dnotify_req->filter = filter;
6645 dnotify_req->multishot = multishot;
6646 spin_lock(&GlobalMid_Lock);
6647 list_add_tail(&dnotify_req->lhead,
6648 &GlobalDnotifyReqList);
6649 spin_unlock(&GlobalMid_Lock);
6650 } else
6651 rc = -ENOMEM;
6652 }
6653 cifs_buf_release(pSMB);
6654 return rc;
6655}
6656#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */