blob: 071e2f21a7db7e4713f79278a8ea2c7d7418ee9a [file] [log] [blame]
Steve French929be902021-06-18 00:31:49 -05001// SPDX-License-Identifier: LGPL-2.1
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
12 /* These are mostly routines that operate on a pathname, or on a tree id */
13 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000014 /* treated slightly differently for reconnection purposes since we never */
15 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17#include <linux/fs.h>
18#include <linux/kernel.h>
19#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040022#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040023#include <linux/swap.h>
24#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080025#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "cifspdu.h"
27#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000028#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "cifsproto.h"
30#include "cifs_unicode.h"
31#include "cifs_debug.h"
Pavel Shilovskyd9191312019-12-10 11:44:52 -080032#include "smb2proto.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040033#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070034#include "smbdirect.h"
Paulo Alcantara08744012018-11-14 17:24:29 -020035#ifdef CONFIG_CIFS_DFS_UPCALL
36#include "dfs_cache.h"
37#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39#ifdef CONFIG_CIFS_POSIX
40static struct {
41 int index;
42 char *name;
43} protocols[] = {
Steve French50c2f752007-07-13 00:33:32 +000044 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000045 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 {BAD_PROT, "\2"}
47};
48#else
49static struct {
50 int index;
51 char *name;
52} protocols[] = {
Steve French790fe572007-07-07 19:25:05 +000053 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 {BAD_PROT, "\2"}
55};
56#endif
57
Steve French39798772006-05-31 22:40:51 +000058/* define the number of elements in the cifs dialect array */
59#ifdef CONFIG_CIFS_POSIX
Steve French39798772006-05-31 22:40:51 +000060#define CIFS_NUM_PROT 2
Steve French39798772006-05-31 22:40:51 +000061#else /* not posix */
Steve French39798772006-05-31 22:40:51 +000062#define CIFS_NUM_PROT 1
Steve French39798772006-05-31 22:40:51 +000063#endif /* CIFS_POSIX */
64
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040065/*
66 * Mark as invalid, all open files on tree connections since they
67 * were closed when session to server was lost.
68 */
69void
70cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
72 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000073 struct list_head *tmp;
74 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Shyam Prasad N73f9bfb2021-07-19 17:37:52 +000076 /* only send once per connect */
77 spin_lock(&cifs_tcp_ses_lock);
78 if (tcon->ses->status != CifsGood ||
79 tcon->tidStatus != CifsNeedReconnect) {
80 spin_unlock(&cifs_tcp_ses_lock);
81 return;
82 }
83 tcon->tidStatus = CifsInFilesInvalidate;
84 spin_unlock(&cifs_tcp_ses_lock);
85
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040086 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -050087 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040088 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000089 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000090 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040091 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 }
Steve French3afca262016-09-22 18:58:16 -050093 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -050094
Ronnie Sahlberga93864d2018-06-14 06:48:35 +100095 mutex_lock(&tcon->crfid.fid_mutex);
96 tcon->crfid.is_valid = false;
Pavel Shilovskyd9191312019-12-10 11:44:52 -080097 /* cached handle is not valid, so SMB2_CLOSE won't be sent below */
Ronnie Sahlberg45c0f1a2021-03-09 09:07:29 +100098 close_cached_dir_lease_locked(&tcon->crfid);
Ronnie Sahlberga93864d2018-06-14 06:48:35 +100099 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
100 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -0500101
Shyam Prasad N73f9bfb2021-07-19 17:37:52 +0000102 spin_lock(&cifs_tcp_ses_lock);
103 if (tcon->tidStatus == CifsInFilesInvalidate)
104 tcon->tidStatus = CifsNeedTcon;
105 spin_unlock(&cifs_tcp_ses_lock);
106
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400107 /*
108 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
109 * to this tcon.
110 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
Jeff Layton9162ab22009-09-03 12:07:17 -0400113/* reconnect the socket, tcon, and smb session if needed */
114static int
Steve French96daf2b2011-05-27 04:34:02 +0000115cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400116{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400117 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000118 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400119 struct TCP_Server_Info *server;
120 struct nls_table *nls_codepage;
Paulo Alcantara08744012018-11-14 17:24:29 -0200121 int retries;
Jeff Layton9162ab22009-09-03 12:07:17 -0400122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000138 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton9162ab22009-09-03 12:07:17 -0400139 if (tcon->tidStatus == CifsExiting) {
140 if (smb_command != SMB_COM_WRITE_ANDX &&
141 smb_command != SMB_COM_OPEN_ANDX &&
142 smb_command != SMB_COM_TREE_DISCONNECT) {
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000143 spin_unlock(&cifs_tcp_ses_lock);
Joe Perchesf96637b2013-05-04 22:12:25 -0500144 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
145 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400146 return -ENODEV;
147 }
148 }
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000149 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton9162ab22009-09-03 12:07:17 -0400150
Paulo Alcantara08744012018-11-14 17:24:29 -0200151 retries = server->nr_targets;
152
Jeff Layton9162ab22009-09-03 12:07:17 -0400153 /*
Paulo Alcantara08744012018-11-14 17:24:29 -0200154 * Give demultiplex thread up to 10 seconds to each target available for
155 * reconnect -- should be greater than cifs socket timeout which is 7
156 * seconds.
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 */
158 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300159 rc = wait_event_interruptible_timeout(server->response_q,
160 (server->tcpStatus != CifsNeedReconnect),
161 10 * HZ);
162 if (rc < 0) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700163 cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
164 __func__);
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300165 return -ERESTARTSYS;
166 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400167
Steve Frenchfd88ce92011-04-12 01:01:14 +0000168 /* are we still trying to reconnect? */
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000169 spin_lock(&cifs_tcp_ses_lock);
170 if (server->tcpStatus != CifsNeedReconnect) {
171 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton9162ab22009-09-03 12:07:17 -0400172 break;
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000173 }
174 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton9162ab22009-09-03 12:07:17 -0400175
Ronnie Sahlberg09c40b12020-02-06 13:55:19 +1000176 if (retries && --retries)
Paulo Alcantara08744012018-11-14 17:24:29 -0200177 continue;
178
Jeff Layton9162ab22009-09-03 12:07:17 -0400179 /*
180 * on "soft" mounts we wait once. Hard mounts keep
181 * retrying until process is killed or server comes
182 * back on-line
183 */
Jeff Laytond4025392011-02-07 08:54:35 -0500184 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500185 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400186 return -EHOSTDOWN;
187 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200188 retries = server->nr_targets;
Jeff Layton9162ab22009-09-03 12:07:17 -0400189 }
190
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000191 spin_lock(&ses->chan_lock);
192 if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
193 spin_unlock(&ses->chan_lock);
Jeff Layton9162ab22009-09-03 12:07:17 -0400194 return 0;
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000195 }
196 spin_unlock(&ses->chan_lock);
Jeff Layton9162ab22009-09-03 12:07:17 -0400197
198 nls_codepage = load_nls_default();
199
200 /*
Samuel Cabrero76e75272017-07-11 12:44:39 +0200201 * Recheck after acquire mutex. If another thread is negotiating
202 * and the server never sends an answer the socket will be closed
203 * and tcpStatus set to reconnect.
204 */
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000205 spin_lock(&cifs_tcp_ses_lock);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200206 if (server->tcpStatus == CifsNeedReconnect) {
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000207 spin_unlock(&cifs_tcp_ses_lock);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200208 rc = -EHOSTDOWN;
Samuel Cabrero76e75272017-07-11 12:44:39 +0200209 goto out;
210 }
Shyam Prasad N080dc5e2021-07-19 17:05:53 +0000211 spin_unlock(&cifs_tcp_ses_lock);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200212
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000213 /*
214 * need to prevent multiple threads trying to simultaneously
215 * reconnect the same SMB session
216 */
217 spin_lock(&ses->chan_lock);
218 if (!cifs_chan_needs_reconnect(ses, server)) {
219 spin_unlock(&ses->chan_lock);
Shyam Prasad Nf486ef82021-07-19 13:54:16 +0000220
221 /* this means that we only need to tree connect */
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000222 if (tcon->need_reconnect)
223 goto skip_sess_setup;
224
225 rc = -EHOSTDOWN;
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000226 goto out;
227 }
228 spin_unlock(&ses->chan_lock);
229
Shyam Prasad N73f9bfb2021-07-19 17:37:52 +0000230 mutex_lock(&ses->session_mutex);
Shyam Prasad Nf486ef82021-07-19 13:54:16 +0000231 rc = cifs_negotiate_protocol(0, ses, server);
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000232 if (!rc)
Shyam Prasad Nf486ef82021-07-19 13:54:16 +0000233 rc = cifs_setup_session(0, ses, server, nls_codepage);
Jeff Layton9162ab22009-09-03 12:07:17 -0400234
235 /* do we need to reconnect tcon? */
236 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000237 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400238 goto out;
239 }
240
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000241skip_sess_setup:
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400242 cifs_mark_open_files_invalid(tcon);
Stefan Metzmacher565674d2020-07-21 09:36:38 -0300243 rc = cifs_tree_connect(0, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000244 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500245 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400246
Steve Frenchc318e6c2018-04-04 14:08:52 -0500247 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700248 pr_warn_once("reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400249 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500250 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400251
Jeff Layton9162ab22009-09-03 12:07:17 -0400252 atomic_inc(&tconInfoReconnectCount);
253
254 /* tell server Unix caps we support */
Stefan Metzmacher864138c2020-02-24 14:15:00 +0100255 if (cap_unix(ses))
Jeff Layton9162ab22009-09-03 12:07:17 -0400256 reset_cifs_unix_caps(0, tcon, NULL, NULL);
257
258 /*
259 * Removed call to reopen open files here. It is safer (and faster) to
260 * reopen files one at a time as needed in read and write.
261 *
262 * FIXME: what about file locks? don't we need to reclaim them ASAP?
263 */
264
265out:
266 /*
267 * Check if handle based operation so we know whether we can continue
268 * or not without returning to caller to reset file handle
269 */
270 switch (smb_command) {
271 case SMB_COM_READ_ANDX:
272 case SMB_COM_WRITE_ANDX:
273 case SMB_COM_CLOSE:
274 case SMB_COM_FIND_CLOSE2:
275 case SMB_COM_LOCKING_ANDX:
276 rc = -EAGAIN;
277 }
278
279 unload_nls(nls_codepage);
280 return rc;
281}
282
Steve Frenchad7a2922008-02-07 23:25:02 +0000283/* Allocate and return pointer to an SMB request buffer, and set basic
284 SMB information in the SMB header. If the return code is zero, this
285 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286static int
Steve French96daf2b2011-05-27 04:34:02 +0000287small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000288 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
Jeff Laytonf5695992010-09-29 15:27:08 -0400290 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Jeff Layton9162ab22009-09-03 12:07:17 -0400292 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000293 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return rc;
295
296 *request_buf = cifs_small_buf_get();
297 if (*request_buf == NULL) {
298 /* BB should we add a retry in here if not a writepage? */
299 return -ENOMEM;
300 }
301
Steve French63135e02007-07-17 17:34:02 +0000302 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000303 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Steve French790fe572007-07-07 19:25:05 +0000305 if (tcon != NULL)
306 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700307
Jeff Laytonf5695992010-09-29 15:27:08 -0400308 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000309}
310
Steve French12b3b8f2006-02-09 21:12:47 +0000311int
Steve French50c2f752007-07-13 00:33:32 +0000312small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000313 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000314{
315 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000316 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000317
Steve French5815449d2006-02-14 01:36:20 +0000318 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000319 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000320 return rc;
321
Steve French04fdabe2006-02-10 05:52:50 +0000322 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400323 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000324 if (ses->capabilities & CAP_UNICODE)
325 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000326 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000327 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
328
329 /* uid, tid can stay at zero as set in header assemble */
330
Steve French50c2f752007-07-13 00:33:32 +0000331 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000332 this function is used after 1st of session setup requests */
333
334 return rc;
335}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337/* If the return code is zero, this function must fill in request_buf pointer */
338static int
Steve French96daf2b2011-05-27 04:34:02 +0000339__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400340 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 *request_buf = cifs_buf_get();
343 if (*request_buf == NULL) {
344 /* BB should we add a retry in here if not a writepage? */
345 return -ENOMEM;
346 }
347 /* Although the original thought was we needed the response buf for */
348 /* potential retries of smb operations it turns out we can determine */
349 /* from the mid flags when the request buffer can be resent without */
350 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000351 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000352 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000355 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Steve French790fe572007-07-07 19:25:05 +0000357 if (tcon != NULL)
358 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700359
Jeff Laytonf5695992010-09-29 15:27:08 -0400360 return 0;
361}
362
363/* If the return code is zero, this function must fill in request_buf pointer */
364static int
Steve French96daf2b2011-05-27 04:34:02 +0000365smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400366 void **request_buf, void **response_buf)
367{
368 int rc;
369
370 rc = cifs_reconnect_tcon(tcon, smb_command);
371 if (rc)
372 return rc;
373
374 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
375}
376
377static int
Steve French96daf2b2011-05-27 04:34:02 +0000378smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400379 void **request_buf, void **response_buf)
380{
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000381 spin_lock(&tcon->ses->chan_lock);
382 if (cifs_chan_needs_reconnect(tcon->ses, tcon->ses->server) ||
383 tcon->need_reconnect) {
384 spin_unlock(&tcon->ses->chan_lock);
Jeff Laytonf5695992010-09-29 15:27:08 -0400385 return -EHOSTDOWN;
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000386 }
387 spin_unlock(&tcon->ses->chan_lock);
Jeff Laytonf5695992010-09-29 15:27:08 -0400388
389 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390}
391
Steve French50c2f752007-07-13 00:33:32 +0000392static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
Jeff Layton12df83c2011-01-20 13:36:51 -0500394 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Jeff Layton12df83c2011-01-20 13:36:51 -0500396 /* check for plausible wct */
397 if (pSMB->hdr.WordCount < 10)
398 goto vt2_err;
399
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500401 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
402 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
403 goto vt2_err;
404
Jeff Layton12df83c2011-01-20 13:36:51 -0500405 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
406 if (total_size >= 512)
407 goto vt2_err;
408
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400409 /* check that bcc is at least as big as parms + data, and that it is
410 * less than negotiated smb buffer
411 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500412 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
413 if (total_size > get_bcc(&pSMB->hdr) ||
414 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
415 goto vt2_err;
416
417 return 0;
418vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000419 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500421 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
Jeff Layton690c5222011-01-20 13:36:51 -0500423
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400424static int
Jeff Layton3f618222013-06-12 19:52:14 -0500425decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400426{
427 int rc = 0;
428 u16 count;
429 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500430 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400431
432 count = get_bcc(&pSMBr->hdr);
433 if (count < SMB1_CLIENT_GUID_SIZE)
434 return -EIO;
435
436 spin_lock(&cifs_tcp_ses_lock);
437 if (server->srv_count > 1) {
438 spin_unlock(&cifs_tcp_ses_lock);
439 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
440 cifs_dbg(FYI, "server UID changed\n");
441 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
442 }
443 } else {
444 spin_unlock(&cifs_tcp_ses_lock);
445 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
446 }
447
448 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500449 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400450 } else {
451 count -= SMB1_CLIENT_GUID_SIZE;
452 rc = decode_negTokenInit(
453 pSMBr->u.extended_response.SecurityBlob, count, server);
454 if (rc != 1)
455 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400456 }
457
458 return 0;
459}
460
Jeff Layton9ddec562013-05-26 07:00:58 -0400461int
Jeff Layton38d77c52013-05-26 07:01:00 -0400462cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400463{
Jeff Layton502858822013-06-27 12:45:00 -0400464 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
465 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400466 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
467
468 /*
469 * Is signing required by mnt options? If not then check
470 * global_secflags to see if it is there.
471 */
472 if (!mnt_sign_required)
473 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
474 CIFSSEC_MUST_SIGN);
475
476 /*
477 * If signing is required then it's automatically enabled too,
478 * otherwise, check to see if the secflags allow it.
479 */
480 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
481 (global_secflags & CIFSSEC_MAY_SIGN);
482
483 /* If server requires signing, does client allow it? */
484 if (srv_sign_required) {
485 if (!mnt_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700486 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400487 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400488 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400489 server->sign = true;
490 }
491
492 /* If client requires signing, does server allow it? */
493 if (mnt_sign_required) {
494 if (!srv_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700495 cifs_dbg(VFS, "Server does not support signing!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400496 return -ENOTSUPP;
497 }
498 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400499 }
500
Long Libb4c0412018-04-17 12:17:08 -0700501 if (cifs_rdma_enabled(server) && server->sign)
Joe Perchesa0a30362020-04-14 22:42:53 -0700502 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");
Long Libb4c0412018-04-17 12:17:08 -0700503
Jeff Layton9ddec562013-05-26 07:00:58 -0400504 return 0;
505}
506
Jeff Layton91934002013-05-26 07:00:58 -0400507static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500508should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400509{
Jeff Layton3f618222013-06-12 19:52:14 -0500510 switch (sectype) {
511 case RawNTLMSSP:
512 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400513 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500514 case Unspecified:
515 if (global_secflags &
516 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
517 return true;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500518 fallthrough;
Jeff Layton3f618222013-06-12 19:52:14 -0500519 default:
520 return false;
521 }
Jeff Layton91934002013-05-26 07:00:58 -0400522}
523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524int
Shyam Prasad Nf486ef82021-07-19 13:54:16 +0000525CIFSSMBNegotiate(const unsigned int xid,
526 struct cifs_ses *ses,
527 struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
529 NEGOTIATE_REQ *pSMB;
530 NEGOTIATE_RSP *pSMBr;
531 int rc = 0;
532 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000533 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 u16 count;
535
Jeff Layton3534b852013-05-24 07:41:01 -0400536 if (!server) {
537 WARN(1, "%s: server is NULL!\n", __func__);
538 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Jeff Layton3534b852013-05-24 07:41:01 -0400540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
542 (void **) &pSMB, (void **) &pSMBr);
543 if (rc)
544 return rc;
Steve French750d1152006-06-27 06:28:30 +0000545
Pavel Shilovsky88257362012-05-23 14:01:59 +0400546 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000547 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000548
Jeff Layton3f618222013-06-12 19:52:14 -0500549 if (should_set_ext_sec_flag(ses->sectype)) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700550 cifs_dbg(FYI, "Requesting extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000551 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
552 }
Steve French50c2f752007-07-13 00:33:32 +0000553
Steve French39798772006-05-31 22:40:51 +0000554 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000555 /*
556 * We know that all the name entries in the protocols array
557 * are short (< 16 bytes anyway) and are NUL terminated.
558 */
Steve French50c2f752007-07-13 00:33:32 +0000559 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000560 size_t len = strlen(protocols[i].name) + 1;
561
562 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
563 count += len;
Steve French39798772006-05-31 22:40:51 +0000564 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000565 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 pSMB->ByteCount = cpu_to_le16(count);
567
568 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
569 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000570 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000571 goto neg_err_exit;
572
Jeff Layton9bf67e52010-04-24 07:57:46 -0400573 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500574 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000575 /* Check wct = 1 error case */
Ronnie Sahlberg76a3c922021-08-19 20:34:58 +1000576 if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000577 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000578 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000579 could not negotiate a common dialect */
580 rc = -EOPNOTSUPP;
581 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000582 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000583 /* unknown wct */
584 rc = -EOPNOTSUPP;
585 goto neg_err_exit;
586 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400587 /* else wct == 17, NTLM or better */
588
Steve French96daf2b2011-05-27 04:34:02 +0000589 server->sec_mode = pSMBr->SecurityMode;
590 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500591 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000592
Steve French254e55e2006-06-04 05:53:15 +0000593 /* one byte, so no need to convert this or EncryptionKeyLen from
594 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300595 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
596 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400597 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000598 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400599 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800600 /* set up max_read for readpages check */
601 server->max_read = server->maxBuf;
Steve Frencheca6acf2009-02-20 05:43:09 +0000602 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500603 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000604 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000605 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
606 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400607
Jeff Laytone598d1d82013-05-26 07:00:59 -0400608 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
609 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500610 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000611 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100612 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
613 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400614 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500615 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400616 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000617 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400618 } else {
619 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000620 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400621 }
Steve French254e55e2006-06-04 05:53:15 +0000622
Jeff Layton9ddec562013-05-26 07:00:58 -0400623 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400624 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000625neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700626 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000627
Joe Perchesf96637b2013-05-04 22:12:25 -0500628 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return rc;
630}
631
632int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400633CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
635 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Joe Perchesf96637b2013-05-04 22:12:25 -0500638 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500639
640 /* BB: do we need to check this? These should never be NULL. */
641 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
642 return -EIO;
643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500645 * No need to return error on this operation if tid invalidated and
646 * closed on server already e.g. due to tcp session crashing. Also,
647 * the tcon is no longer on the list, so no need to take lock before
648 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 */
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000650 spin_lock(&tcon->ses->chan_lock);
651 if ((tcon->need_reconnect) || CIFS_ALL_CHANS_NEED_RECONNECT(tcon->ses)) {
652 spin_unlock(&tcon->ses->chan_lock);
653 return -EIO;
654 }
655 spin_unlock(&tcon->ses->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Steve French50c2f752007-07-13 00:33:32 +0000657 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700658 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500659 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 return rc;
Steve French133672e2007-11-13 22:41:37 +0000661
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400662 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700663 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500665 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Steve French50c2f752007-07-13 00:33:32 +0000667 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500668 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 if (rc == -EAGAIN)
670 rc = 0;
671
672 return rc;
673}
674
Jeff Layton766fdbb2011-01-11 07:24:21 -0500675/*
676 * This is a no-op for now. We're not really interested in the reply, but
677 * rather in the fact that the server sent one and that server->lstrp
678 * gets updated.
679 *
680 * FIXME: maybe we should consider checking that the reply matches request?
681 */
682static void
683cifs_echo_callback(struct mid_q_entry *mid)
684{
685 struct TCP_Server_Info *server = mid->callback_data;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800686 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500687
688 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800689 add_credits(server, &credits, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500690}
691
692int
693CIFSSMBEcho(struct TCP_Server_Info *server)
694{
695 ECHO_REQ *smb;
696 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800697 struct kvec iov[2];
698 struct smb_rqst rqst = { .rq_iov = iov,
699 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500700
Joe Perchesf96637b2013-05-04 22:12:25 -0500701 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500702
703 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
704 if (rc)
705 return rc;
706
Steve French26c9cb62017-05-02 13:35:20 -0500707 if (server->capabilities & CAP_UNICODE)
708 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
709
Jeff Layton766fdbb2011-01-11 07:24:21 -0500710 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000711 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500712 smb->hdr.WordCount = 1;
713 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400714 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500715 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000716 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800717
718 iov[0].iov_len = 4;
719 iov[0].iov_base = smb;
720 iov[1].iov_len = get_rfc1002_length(smb);
721 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500722
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800723 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +1000724 server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500726 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500727
728 cifs_small_buf_release(smb);
729
730 return rc;
731}
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400734CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 LOGOFF_ANDX_REQ *pSMB;
737 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Joe Perchesf96637b2013-05-04 22:12:25 -0500739 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500740
741 /*
742 * BB: do we need to check validity of ses and server? They should
743 * always be valid since we have an active reference. If not, that
744 * should probably be a BUG()
745 */
746 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 return -EIO;
748
Steve Frenchd7b619c2010-02-25 05:36:46 +0000749 mutex_lock(&ses->session_mutex);
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000750 spin_lock(&ses->chan_lock);
751 if (CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
752 spin_unlock(&ses->chan_lock);
Steve French3b795212008-11-13 19:45:32 +0000753 goto session_already_dead; /* no need to send SMBlogoff if uid
754 already closed due to reconnect */
Shyam Prasad Nd1a931c2021-07-19 12:46:53 +0000755 }
756 spin_unlock(&ses->chan_lock);
757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
759 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000760 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return rc;
762 }
763
Pavel Shilovsky88257362012-05-23 14:01:59 +0400764 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700765
Jeff Layton38d77c52013-05-26 07:01:00 -0400766 if (ses->server->sign)
767 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 pSMB->hdr.Uid = ses->Suid;
770
771 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400772 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700773 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000774session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000775 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000778 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 error */
780 if (rc == -EAGAIN)
781 rc = 0;
782 return rc;
783}
784
785int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400786CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
787 const char *fileName, __u16 type,
788 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000789{
790 TRANSACTION2_SPI_REQ *pSMB = NULL;
791 TRANSACTION2_SPI_RSP *pSMBr = NULL;
792 struct unlink_psx_rq *pRqD;
793 int name_len;
794 int rc = 0;
795 int bytes_returned = 0;
796 __u16 params, param_offset, offset, byte_count;
797
Joe Perchesf96637b2013-05-04 22:12:25 -0500798 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000799PsxDelete:
800 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
801 (void **) &pSMBr);
802 if (rc)
803 return rc;
804
805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
806 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600807 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
808 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000809 name_len++; /* trailing null */
810 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000811 } else {
812 name_len = copy_path_name(pSMB->FileName, fileName);
Steve French2d785a52007-07-15 01:48:57 +0000813 }
814
815 params = 6 + name_len;
816 pSMB->MaxParameterCount = cpu_to_le16(2);
817 pSMB->MaxDataCount = 0; /* BB double check this with jra */
818 pSMB->MaxSetupCount = 0;
819 pSMB->Reserved = 0;
820 pSMB->Flags = 0;
821 pSMB->Timeout = 0;
822 pSMB->Reserved2 = 0;
823 param_offset = offsetof(struct smb_com_transaction2_spi_req,
824 InformationLevel) - 4;
825 offset = param_offset + params;
826
Steve French7b09d4e2021-07-22 14:35:15 -0500827 /* Setup pointer to Request Data (inode type).
828 * Note that SMB offsets are from the beginning of SMB which is 4 bytes
829 * in, after RFC1001 field
830 */
831 pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4);
Steve French2d785a52007-07-15 01:48:57 +0000832 pRqD->type = cpu_to_le16(type);
833 pSMB->ParameterOffset = cpu_to_le16(param_offset);
834 pSMB->DataOffset = cpu_to_le16(offset);
835 pSMB->SetupCount = 1;
836 pSMB->Reserved3 = 0;
837 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
838 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
839
840 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
841 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
842 pSMB->ParameterCount = cpu_to_le16(params);
843 pSMB->TotalParameterCount = pSMB->ParameterCount;
844 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
845 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000846 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000847 pSMB->ByteCount = cpu_to_le16(byte_count);
848 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
849 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000850 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500851 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000852 cifs_buf_release(pSMB);
853
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400854 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000855
856 if (rc == -EAGAIN)
857 goto PsxDelete;
858
859 return rc;
860}
861
862int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700863CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
864 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 DELETE_FILE_REQ *pSMB = NULL;
867 DELETE_FILE_RSP *pSMBr = NULL;
868 int rc = 0;
869 int bytes_returned;
870 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500871 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873DelFileRetry:
874 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
875 (void **) &pSMBr);
876 if (rc)
877 return rc;
878
879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700880 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
881 PATH_MAX, cifs_sb->local_nls,
882 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 name_len++; /* trailing null */
884 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000885 } else {
886 name_len = copy_path_name(pSMB->fileName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 }
888 pSMB->SearchAttributes =
889 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
890 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000891 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 pSMB->ByteCount = cpu_to_le16(name_len + 1);
893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400895 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000896 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500897 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
899 cifs_buf_release(pSMB);
900 if (rc == -EAGAIN)
901 goto DelFileRetry;
902
903 return rc;
904}
905
906int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400907CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
908 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
910 DELETE_DIRECTORY_REQ *pSMB = NULL;
911 DELETE_DIRECTORY_RSP *pSMBr = NULL;
912 int rc = 0;
913 int bytes_returned;
914 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500915 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Joe Perchesf96637b2013-05-04 22:12:25 -0500917 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918RmDirRetry:
919 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
920 (void **) &pSMBr);
921 if (rc)
922 return rc;
923
924 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400925 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
926 PATH_MAX, cifs_sb->local_nls,
927 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 name_len++; /* trailing null */
929 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000930 } else {
931 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 }
933
934 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000935 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 pSMB->ByteCount = cpu_to_le16(name_len + 1);
937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400939 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000940 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500941 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 cifs_buf_release(pSMB);
944 if (rc == -EAGAIN)
945 goto RmDirRetry;
946 return rc;
947}
948
949int
Steve Frenchc3ca78e2019-09-25 00:32:13 -0500950CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
951 struct cifs_tcon *tcon, const char *name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300952 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 int rc = 0;
955 CREATE_DIRECTORY_REQ *pSMB = NULL;
956 CREATE_DIRECTORY_RSP *pSMBr = NULL;
957 int bytes_returned;
958 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500959 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Joe Perchesf96637b2013-05-04 22:12:25 -0500961 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962MkDirRetry:
963 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
964 (void **) &pSMBr);
965 if (rc)
966 return rc;
967
968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600969 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300970 PATH_MAX, cifs_sb->local_nls,
971 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 name_len++; /* trailing null */
973 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000974 } else {
975 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 }
977
978 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000979 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 pSMB->ByteCount = cpu_to_le16(name_len + 1);
981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400983 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000984 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500985 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700986
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 cifs_buf_release(pSMB);
988 if (rc == -EAGAIN)
989 goto MkDirRetry;
990 return rc;
991}
992
Steve French2dd29d32007-04-23 22:07:35 +0000993int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400994CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
995 __u32 posix_flags, __u64 mode, __u16 *netfid,
996 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
997 const char *name, const struct nls_table *nls_codepage,
998 int remap)
Steve French2dd29d32007-04-23 22:07:35 +0000999{
1000 TRANSACTION2_SPI_REQ *pSMB = NULL;
1001 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1002 int name_len;
1003 int rc = 0;
1004 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001005 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001006 OPEN_PSX_REQ *pdata;
1007 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001008
Joe Perchesf96637b2013-05-04 22:12:25 -05001009 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001010PsxCreat:
1011 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1012 (void **) &pSMBr);
1013 if (rc)
1014 return rc;
1015
1016 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1017 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001018 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1019 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001020 name_len++; /* trailing null */
1021 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001022 } else {
1023 name_len = copy_path_name(pSMB->FileName, name);
Steve French2dd29d32007-04-23 22:07:35 +00001024 }
1025
1026 params = 6 + name_len;
1027 count = sizeof(OPEN_PSX_REQ);
1028 pSMB->MaxParameterCount = cpu_to_le16(2);
1029 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1030 pSMB->MaxSetupCount = 0;
1031 pSMB->Reserved = 0;
1032 pSMB->Flags = 0;
1033 pSMB->Timeout = 0;
1034 pSMB->Reserved2 = 0;
1035 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001036 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001037 offset = param_offset + params;
Steve French21a64912021-07-22 13:50:41 -05001038 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
1039 pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001040 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001041 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001042 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001043 pdata->OpenFlags = cpu_to_le32(*pOplock);
1044 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1045 pSMB->DataOffset = cpu_to_le16(offset);
1046 pSMB->SetupCount = 1;
1047 pSMB->Reserved3 = 0;
1048 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1049 byte_count = 3 /* pad */ + params + count;
1050
1051 pSMB->DataCount = cpu_to_le16(count);
1052 pSMB->ParameterCount = cpu_to_le16(params);
1053 pSMB->TotalDataCount = pSMB->DataCount;
1054 pSMB->TotalParameterCount = pSMB->ParameterCount;
1055 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1056 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001057 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001058 pSMB->ByteCount = cpu_to_le16(byte_count);
1059 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1061 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001062 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001063 goto psx_create_err;
1064 }
1065
Joe Perchesf96637b2013-05-04 22:12:25 -05001066 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001067 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1068
Jeff Layton820a8032011-05-04 08:05:26 -04001069 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001070 rc = -EIO; /* bad smb */
1071 goto psx_create_err;
1072 }
1073
1074 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001075 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001076 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001077
Steve French2dd29d32007-04-23 22:07:35 +00001078 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001079 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001080 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1081 /* Let caller know file was created so we can set the mode. */
1082 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001083 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001084 *pOplock |= CIFS_CREATE_ACTION;
1085 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001086 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1087 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001088 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001089 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001090 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001091 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001092 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001093 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001094 goto psx_create_err;
1095 }
Steve French50c2f752007-07-13 00:33:32 +00001096 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001097 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001098 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001099 }
Steve French2dd29d32007-04-23 22:07:35 +00001100
1101psx_create_err:
1102 cifs_buf_release(pSMB);
1103
Steve French65bc98b2009-07-10 15:27:25 +00001104 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001105 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001106 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001107 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001108
1109 if (rc == -EAGAIN)
1110 goto PsxCreat;
1111
Steve French50c2f752007-07-13 00:33:32 +00001112 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001113}
1114
Steve Frencha9d02ad2005-08-24 23:06:05 -07001115static __u16 convert_disposition(int disposition)
1116{
1117 __u16 ofun = 0;
1118
1119 switch (disposition) {
1120 case FILE_SUPERSEDE:
1121 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1122 break;
1123 case FILE_OPEN:
1124 ofun = SMBOPEN_OAPPEND;
1125 break;
1126 case FILE_CREATE:
1127 ofun = SMBOPEN_OCREATE;
1128 break;
1129 case FILE_OPEN_IF:
1130 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1131 break;
1132 case FILE_OVERWRITE:
1133 ofun = SMBOPEN_OTRUNC;
1134 break;
1135 case FILE_OVERWRITE_IF:
1136 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1137 break;
1138 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001139 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001140 ofun = SMBOPEN_OAPPEND; /* regular open */
1141 }
1142 return ofun;
1143}
1144
Jeff Layton35fc37d2008-05-14 10:22:03 -07001145static int
1146access_flags_to_smbopen_mode(const int access_flags)
1147{
1148 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1149
1150 if (masked_flags == GENERIC_READ)
1151 return SMBOPEN_READ;
1152 else if (masked_flags == GENERIC_WRITE)
1153 return SMBOPEN_WRITE;
1154
1155 /* just go for read/write */
1156 return SMBOPEN_READWRITE;
1157}
1158
Steve Frencha9d02ad2005-08-24 23:06:05 -07001159int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001160SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001161 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001162 const int access_flags, const int create_options, __u16 *netfid,
1163 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 const struct nls_table *nls_codepage, int remap)
1165{
Colin Ian King032e0912021-06-13 15:01:23 +01001166 int rc;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167 OPENX_REQ *pSMB = NULL;
1168 OPENX_RSP *pSMBr = NULL;
1169 int bytes_returned;
1170 int name_len;
1171 __u16 count;
1172
1173OldOpenRetry:
1174 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1175 (void **) &pSMBr);
1176 if (rc)
1177 return rc;
1178
1179 pSMB->AndXCommand = 0xFF; /* none */
1180
1181 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1182 count = 1; /* account for one byte pad to word boundary */
1183 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001184 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1185 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 name_len++; /* trailing null */
1187 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001188 } else {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001189 count = 0; /* no pad */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001190 name_len = copy_path_name(pSMB->fileName, fileName);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001191 }
1192 if (*pOplock & REQ_OPLOCK)
1193 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001194 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001195 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001196
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001198 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001199 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1200 /* set file as system file if special file such
1201 as fifo and server expecting SFU style and
1202 no Unix extensions */
1203
Steve French790fe572007-07-07 19:25:05 +00001204 if (create_options & CREATE_OPTION_SPECIAL)
1205 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001206 else /* BB FIXME BB */
1207 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208
Jeff Layton67750fb2008-05-09 22:28:02 +00001209 if (create_options & CREATE_OPTION_READONLY)
1210 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211
1212 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001213/* pSMB->CreateOptions = cpu_to_le32(create_options &
1214 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001216
1217 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001218 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001220 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221
1222 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001224 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001225 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001227 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228 } else {
1229 /* BB verify if wct == 15 */
1230
Steve French582d21e2008-05-13 04:54:12 +00001231/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232
1233 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1234 /* Let caller know file was created so we can set the mode. */
1235 /* Do we care about the CreateAction in any other cases? */
1236 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001237/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238 *pOplock |= CIFS_CREATE_ACTION; */
1239 /* BB FIXME END */
1240
Steve French790fe572007-07-07 19:25:05 +00001241 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1243 pfile_info->LastAccessTime = 0; /* BB fixme */
1244 pfile_info->LastWriteTime = 0; /* BB fixme */
1245 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001246 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001247 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001249 pfile_info->AllocationSize =
1250 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1251 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001253 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 }
1255 }
1256
1257 cifs_buf_release(pSMB);
1258 if (rc == -EAGAIN)
1259 goto OldOpenRetry;
1260 return rc;
1261}
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001264CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1265 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266{
Colin Ian King1afdea42019-07-23 16:09:19 +01001267 int rc;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001268 OPEN_REQ *req = NULL;
1269 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 int bytes_returned;
1271 int name_len;
1272 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001273 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1274 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001275 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001276 const struct nls_table *nls = cifs_sb->local_nls;
1277 int create_options = oparms->create_options;
1278 int desired_access = oparms->desired_access;
1279 int disposition = oparms->disposition;
1280 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
1282openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001283 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1284 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 if (rc)
1286 return rc;
1287
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001288 /* no commands go after this */
1289 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001291 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1292 /* account for one byte pad to word boundary */
1293 count = 1;
1294 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1295 path, PATH_MAX, nls, remap);
1296 /* trailing null */
1297 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001299 req->NameLength = cpu_to_le16(name_len);
1300 } else {
1301 /* BB improve check for buffer overruns BB */
1302 /* no pad */
1303 count = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001304 name_len = copy_path_name(req->fileName, path);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001305 req->NameLength = cpu_to_le16(name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001307
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001308 if (*oplock & REQ_OPLOCK)
1309 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1310 else if (*oplock & REQ_BATCHOPLOCK)
1311 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1312
1313 req->DesiredAccess = cpu_to_le32(desired_access);
1314 req->AllocationSize = 0;
1315
1316 /*
1317 * Set file as system file if special file such as fifo and server
1318 * expecting SFU style and no Unix extensions.
1319 */
1320 if (create_options & CREATE_OPTION_SPECIAL)
1321 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1322 else
1323 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1324
1325 /*
1326 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1327 * sensitive checks for other servers such as Samba.
1328 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001330 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Jeff Layton67750fb2008-05-09 22:28:02 +00001332 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001333 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001334
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001335 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1336 req->CreateDisposition = cpu_to_le32(disposition);
1337 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1338
Steve French09d1db52005-04-28 22:41:08 -07001339 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001340 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1341 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
1343 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001344 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001346 req->ByteCount = cpu_to_le16(count);
1347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1348 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001349 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001351 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001352 cifs_buf_release(req);
1353 if (rc == -EAGAIN)
1354 goto openRetry;
1355 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001357
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001358 /* 1 byte no need to le_to_cpu */
1359 *oplock = rsp->OplockLevel;
1360 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001361 oparms->fid->netfid = rsp->Fid;
Aurelien Aptel86f740f2020-02-21 11:19:06 +01001362 oparms->fid->access = desired_access;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001363
1364 /* Let caller know file was created so we can set the mode. */
1365 /* Do we care about the CreateAction in any other cases? */
1366 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1367 *oplock |= CIFS_CREATE_ACTION;
1368
1369 if (buf) {
1370 /* copy from CreationTime to Attributes */
1371 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1372 /* the file_info buf is endian converted by caller */
1373 buf->AllocationSize = rsp->AllocationSize;
1374 buf->EndOfFile = rsp->EndOfFile;
1375 buf->NumberOfLinks = cpu_to_le32(1);
1376 buf->DeletePending = 0;
1377 }
1378
1379 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 return rc;
1381}
1382
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001383/*
1384 * Discard any remaining data in the current SMB. To do this, we borrow the
1385 * current bigbuf.
1386 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001387int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001388cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001389{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001390 unsigned int rfclen = server->pdu_size;
1391 int remaining = rfclen + server->vals->header_preamble_size -
1392 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001393
1394 while (remaining > 0) {
1395 int length;
1396
David Howellscf0604a2021-02-04 00:15:21 -06001397 length = cifs_discard_from_socket(server,
1398 min_t(size_t, remaining,
1399 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001400 if (length < 0)
1401 return length;
1402 server->total_read += length;
1403 remaining -= length;
1404 }
1405
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001406 return 0;
1407}
1408
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001409static int
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001410__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1411 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001412{
1413 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001414
Pavel Shilovsky350be252017-04-10 10:31:33 -07001415 length = cifs_discard_remaining_data(server);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001416 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001417 mid->resp_buf = server->smallbuf;
1418 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001419 return length;
1420}
1421
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001422static int
1423cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1424{
1425 struct cifs_readdata *rdata = mid->callback_data;
1426
1427 return __cifs_readv_discard(server, mid, rdata->result);
1428}
1429
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001430int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001431cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1432{
1433 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001434 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001435 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001436 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001437 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001438 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001439 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440
Joe Perchesf96637b2013-05-04 22:12:25 -05001441 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1442 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443
1444 /*
1445 * read the rest of READ_RSP header (sans Data array), or whatever we
1446 * can if there's not enough data. At this point, we've read down to
1447 * the Mid.
1448 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001449 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001450 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451
Al Viroa6137302016-01-09 19:37:16 -05001452 length = cifs_read_from_socket(server,
1453 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001454 if (length < 0)
1455 return length;
1456 server->total_read += length;
1457
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001458 if (server->ops->is_session_expired &&
1459 server->ops->is_session_expired(buf)) {
Shyam Prasad N183eea22021-07-19 14:14:46 +00001460 cifs_reconnect(server, true);
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001461 return -1;
1462 }
1463
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001464 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -08001465 server->ops->is_status_pending(buf, server)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001466 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001467 return -1;
1468 }
1469
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001470 /* set up first two iov for signature check and to get credits */
1471 rdata->iov[0].iov_base = buf;
Pavel Shilovskybb1bccb2019-01-17 16:18:38 -08001472 rdata->iov[0].iov_len = server->vals->header_preamble_size;
1473 rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1474 rdata->iov[1].iov_len =
1475 server->total_read - server->vals->header_preamble_size;
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001476 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1477 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1478 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1479 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1480
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001482 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001483 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001484 cifs_dbg(FYI, "%s: server returned error %d\n",
1485 __func__, rdata->result);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001486 /* normal error on read response */
1487 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001488 }
1489
1490 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001491 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001492 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1493 __func__, server->total_read,
1494 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001495 rdata->result = -EIO;
1496 return cifs_readv_discard(server, mid);
1497 }
1498
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001499 data_offset = server->ops->read_data_offset(buf) +
1500 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001501 if (data_offset < server->total_read) {
1502 /*
1503 * win2k8 sometimes sends an offset of 0 when the read
1504 * is beyond the EOF. Treat it as if the data starts just after
1505 * the header.
1506 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001507 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1508 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001509 data_offset = server->total_read;
1510 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1511 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001512 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1513 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514 rdata->result = -EIO;
1515 return cifs_readv_discard(server, mid);
1516 }
1517
Joe Perchesf96637b2013-05-04 22:12:25 -05001518 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1519 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520
1521 len = data_offset - server->total_read;
1522 if (len > 0) {
1523 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001524 length = cifs_read_from_socket(server,
1525 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001526 if (length < 0)
1527 return length;
1528 server->total_read += length;
1529 }
1530
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001532#ifdef CONFIG_CIFS_SMB_DIRECT
1533 use_rdma_mr = rdata->mr;
1534#endif
1535 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1536 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001537 /* data_len is corrupt -- discard frame */
1538 rdata->result = -EIO;
1539 return cifs_readv_discard(server, mid);
1540 }
1541
Jeff Layton8321fec2012-09-19 06:22:32 -07001542 length = rdata->read_into_pages(server, rdata, data_len);
1543 if (length < 0)
1544 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545
Jeff Layton8321fec2012-09-19 06:22:32 -07001546 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547
Joe Perchesf96637b2013-05-04 22:12:25 -05001548 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1549 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001550
1551 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001552 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001553 return cifs_readv_discard(server, mid);
1554
1555 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001556 mid->resp_buf = server->smallbuf;
1557 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558 return length;
1559}
1560
1561static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001562cifs_readv_callback(struct mid_q_entry *mid)
1563{
1564 struct cifs_readdata *rdata = mid->callback_data;
1565 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1566 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001567 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1568 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001569 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001570 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001571 .rq_npages = rdata->nr_pages,
1572 .rq_pagesz = rdata->pagesz,
1573 .rq_tailsz = rdata->tailsz };
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001574 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001575
Joe Perchesf96637b2013-05-04 22:12:25 -05001576 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1577 __func__, mid->mid, mid->mid_state, rdata->result,
1578 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001579
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001580 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001581 case MID_RESPONSE_RECEIVED:
1582 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001583 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001584 int rc = 0;
1585
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001586 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001587 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001588 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001589 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1590 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001591 }
1592 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001593 task_io_account_read(rdata->got_bytes);
1594 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001595 break;
1596 case MID_REQUEST_SUBMITTED:
1597 case MID_RETRY_NEEDED:
1598 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001599 if (server->sign && rdata->got_bytes)
1600 /* reset bytes number since we can not check a sign */
1601 rdata->got_bytes = 0;
1602 /* FIXME: should this be counted toward the initiating task? */
1603 task_io_account_read(rdata->got_bytes);
1604 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001605 break;
1606 default:
1607 rdata->result = -EIO;
1608 }
1609
Jeff Laytonda472fc2012-03-23 14:40:53 -04001610 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001611 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001612 add_credits(server, &credits, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001613}
1614
1615/* cifs_async_readv - send an async write, and set up mid to handle result */
1616int
1617cifs_async_readv(struct cifs_readdata *rdata)
1618{
1619 int rc;
1620 READ_REQ *smb = NULL;
1621 int wct;
1622 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001623 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1624 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625
Joe Perchesf96637b2013-05-04 22:12:25 -05001626 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1627 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001628
1629 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1630 wct = 12;
1631 else {
1632 wct = 10; /* old style read */
1633 if ((rdata->offset >> 32) > 0) {
1634 /* can not handle this big offset for old */
1635 return -EIO;
1636 }
1637 }
1638
1639 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1640 if (rc)
1641 return rc;
1642
1643 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1644 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1645
1646 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001647 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001648 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1649 if (wct == 12)
1650 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1651 smb->Remaining = 0;
1652 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1653 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1654 if (wct == 12)
1655 smb->ByteCount = 0;
1656 else {
1657 /* old style read */
1658 struct smb_com_readx_req *smbr =
1659 (struct smb_com_readx_req *)smb;
1660 smbr->ByteCount = 0;
1661 }
1662
1663 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001664 rdata->iov[0].iov_base = smb;
1665 rdata->iov[0].iov_len = 4;
1666 rdata->iov[1].iov_base = (char *)smb + 4;
1667 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001668
Jeff Layton6993f742012-05-16 07:13:17 -04001669 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001670 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08001671 cifs_readv_callback, NULL, rdata, 0, NULL);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001672
1673 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001674 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001675 else
1676 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001677
1678 cifs_small_buf_release(smb);
1679 return rc;
1680}
1681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001683CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1684 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685{
1686 int rc = -EACCES;
1687 READ_REQ *pSMB = NULL;
1688 READ_RSP *pSMBr = NULL;
1689 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001690 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001691 int resp_buf_type = 0;
1692 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001693 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001694 __u32 pid = io_parms->pid;
1695 __u16 netfid = io_parms->netfid;
1696 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001697 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001698 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
Joe Perchesf96637b2013-05-04 22:12:25 -05001700 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001701 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001702 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001703 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001704 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001705 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001706 /* can not handle this big offset for old */
1707 return -EIO;
1708 }
1709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001712 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 if (rc)
1714 return rc;
1715
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001716 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1717 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 /* tcon and ses pointer are checked in smb_init */
1720 if (tcon->ses->server == NULL)
1721 return -ECONNABORTED;
1722
Steve Frenchec637e32005-12-12 20:53:18 -08001723 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001725 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001726 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001727 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001728
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 pSMB->Remaining = 0;
1730 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1731 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001732 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001733 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1734 else {
1735 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001736 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001737 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001738 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001739 }
Steve Frenchec637e32005-12-12 20:53:18 -08001740
1741 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001742 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001743 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1744 CIFS_LOG_ERROR, &rsp_iov);
1745 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001746 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001747 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001749 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 } else {
1751 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1752 data_length = data_length << 16;
1753 data_length += le16_to_cpu(pSMBr->DataLength);
1754 *nbytes = data_length;
1755
1756 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001757 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001759 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001760 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 rc = -EIO;
1762 *nbytes = 0;
1763 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001764 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001765 le16_to_cpu(pSMBr->DataOffset);
1766/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001767 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001768 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001769 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001770 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001771 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 }
1773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Steve French790fe572007-07-07 19:25:05 +00001775 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001776 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001777 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001778 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001779 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001780 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001781 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001782 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001783 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001784 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001785
1786 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 since file handle passed in no longer valid */
1788 return rc;
1789}
1790
Steve Frenchec637e32005-12-12 20:53:18 -08001791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001793CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001794 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795{
1796 int rc = -EACCES;
1797 WRITE_REQ *pSMB = NULL;
1798 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001799 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 __u32 bytes_sent;
1801 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001802 __u32 pid = io_parms->pid;
1803 __u16 netfid = io_parms->netfid;
1804 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001805 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001806 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
Steve Frencha24e2d72010-04-03 17:20:21 +00001808 *nbytes = 0;
1809
Joe Perchesf96637b2013-05-04 22:12:25 -05001810 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001811 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001812 return -ECONNABORTED;
1813
Steve French790fe572007-07-07 19:25:05 +00001814 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001815 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001816 else {
Steve French1c955182005-08-30 20:58:07 -07001817 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001818 if ((offset >> 32) > 0) {
1819 /* can not handle big offset for old srv */
1820 return -EIO;
1821 }
1822 }
Steve French1c955182005-08-30 20:58:07 -07001823
1824 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 (void **) &pSMBr);
1826 if (rc)
1827 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001828
1829 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1830 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1831
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 /* tcon and ses pointer are checked in smb_init */
1833 if (tcon->ses->server == NULL)
1834 return -ECONNABORTED;
1835
1836 pSMB->AndXCommand = 0xFF; /* none */
1837 pSMB->Fid = netfid;
1838 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001839 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001840 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 pSMB->Reserved = 0xFFFFFFFF;
1843 pSMB->WriteMode = 0;
1844 pSMB->Remaining = 0;
1845
Steve French50c2f752007-07-13 00:33:32 +00001846 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 can send more if LARGE_WRITE_X capability returned by the server and if
1848 our buffer is big enough or if we convert to iovecs on socket writes
1849 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001850 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1852 } else {
1853 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1854 & ~0xFF;
1855 }
1856
1857 if (bytes_sent > count)
1858 bytes_sent = count;
1859 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001860 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001861 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001862 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001863 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 /* No buffer */
1865 cifs_buf_release(pSMB);
1866 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001867 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001868 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001869 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001870 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001871 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001872
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1874 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001875 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001876
Steve French790fe572007-07-07 19:25:05 +00001877 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001878 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001879 else { /* old style write has byte count 4 bytes earlier
1880 so 4 bytes pad */
1881 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001882 (struct smb_com_writex_req *)pSMB;
1883 pSMBW->ByteCount = cpu_to_le16(byte_count);
1884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885
1886 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001888 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001890 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 } else {
1892 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1893 *nbytes = (*nbytes) << 16;
1894 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301895
1896 /*
1897 * Mask off high 16 bits when bytes written as returned by the
1898 * server is greater than bytes requested by the client. Some
1899 * OS/2 servers are known to set incorrect CountHigh values.
1900 */
1901 if (*nbytes > count)
1902 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 }
1904
1905 cifs_buf_release(pSMB);
1906
Steve French50c2f752007-07-13 00:33:32 +00001907 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 since file handle passed in no longer valid */
1909
1910 return rc;
1911}
1912
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001913void
1914cifs_writedata_release(struct kref *refcount)
1915{
1916 struct cifs_writedata *wdata = container_of(refcount,
1917 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001918#ifdef CONFIG_CIFS_SMB_DIRECT
1919 if (wdata->mr) {
1920 smbd_deregister_mr(wdata->mr);
1921 wdata->mr = NULL;
1922 }
1923#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001924
1925 if (wdata->cfile)
1926 cifsFileInfo_put(wdata->cfile);
1927
Long Li8e7360f2018-05-30 12:47:56 -07001928 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001929 kfree(wdata);
1930}
1931
1932/*
1933 * Write failed with a retryable error. Resend the write request. It's also
1934 * possible that the page was redirtied so re-clean the page.
1935 */
1936static void
1937cifs_writev_requeue(struct cifs_writedata *wdata)
1938{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001939 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001940 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001941 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001942 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001943
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001944 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1945 i = 0;
1946 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001947 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001948 struct cifs_writedata *wdata2;
1949 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001950
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001951 wsize = server->ops->wp_retry_size(inode);
1952 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001953 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001954 if (!nr_pages) {
1955 rc = -ENOTSUPP;
1956 break;
1957 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001958 cur_len = nr_pages * PAGE_SIZE;
1959 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001960 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001961 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001962 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001963 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001964 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001965
1966 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1967 if (!wdata2) {
1968 rc = -ENOMEM;
1969 break;
1970 }
1971
1972 for (j = 0; j < nr_pages; j++) {
1973 wdata2->pages[j] = wdata->pages[i + j];
1974 lock_page(wdata2->pages[j]);
1975 clear_page_dirty_for_io(wdata2->pages[j]);
1976 }
1977
1978 wdata2->sync_mode = wdata->sync_mode;
1979 wdata2->nr_pages = nr_pages;
1980 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001981 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001982 wdata2->tailsz = tailsz;
1983 wdata2->bytes = cur_len;
1984
Aurelien Aptel86f740f2020-02-21 11:19:06 +01001985 rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08001986 &wdata2->cfile);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001987 if (!wdata2->cfile) {
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08001988 cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
1989 rc);
1990 if (!is_retryable_error(rc))
1991 rc = -EBADF;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08001992 } else {
1993 wdata2->pid = wdata2->cfile->pid;
1994 rc = server->ops->async_writev(wdata2,
1995 cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001996 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001997
1998 for (j = 0; j < nr_pages; j++) {
1999 unlock_page(wdata2->pages[j]);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002000 if (rc != 0 && !is_retryable_error(rc)) {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002001 SetPageError(wdata2->pages[j]);
2002 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002003 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002004 }
2005 }
2006
Adam McCoya4813792020-05-13 11:53:30 +00002007 kref_put(&wdata2->refcount, cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002008 if (rc) {
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002009 if (is_retryable_error(rc))
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002010 continue;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002011 i += nr_pages;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002012 break;
2013 }
2014
2015 rest_len -= cur_len;
2016 i += nr_pages;
2017 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002018
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002019 /* cleanup remaining pages from the original wdata */
2020 for (; i < wdata->nr_pages; i++) {
2021 SetPageError(wdata->pages[i]);
2022 end_page_writeback(wdata->pages[i]);
2023 put_page(wdata->pages[i]);
2024 }
2025
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002026 if (rc != 0 && !is_retryable_error(rc))
2027 mapping_set_error(inode->i_mapping, rc);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002028 kref_put(&wdata->refcount, cifs_writedata_release);
2029}
2030
Jeff Laytonc2e87642012-03-23 14:40:55 -04002031void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002032cifs_writev_complete(struct work_struct *work)
2033{
2034 struct cifs_writedata *wdata = container_of(work,
2035 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002036 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002037 int i = 0;
2038
2039 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002040 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002041 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002042 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002043 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2044 wdata->bytes);
2045 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2046 return cifs_writev_requeue(wdata);
2047
2048 for (i = 0; i < wdata->nr_pages; i++) {
2049 struct page *page = wdata->pages[i];
2050 if (wdata->result == -EAGAIN)
2051 __set_page_dirty_nobuffers(page);
2052 else if (wdata->result < 0)
2053 SetPageError(page);
2054 end_page_writeback(page);
Shyam Prasad N18d04062021-08-10 10:22:28 +00002055 cifs_readpage_to_fscache(inode, page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002056 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002057 }
2058 if (wdata->result != -EAGAIN)
2059 mapping_set_error(inode->i_mapping, wdata->result);
2060 kref_put(&wdata->refcount, cifs_writedata_release);
2061}
2062
2063struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002064cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002065{
Long Li8e7360f2018-05-30 12:47:56 -07002066 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002067 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002068 if (pages)
2069 return cifs_writedata_direct_alloc(pages, complete);
2070
2071 return NULL;
2072}
2073
2074struct cifs_writedata *
2075cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2076{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077 struct cifs_writedata *wdata;
2078
Long Li8e7360f2018-05-30 12:47:56 -07002079 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002081 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002083 INIT_LIST_HEAD(&wdata->list);
2084 init_completion(&wdata->done);
2085 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002086 }
2087 return wdata;
2088}
2089
2090/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002091 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002092 * workqueue completion task.
2093 */
2094static void
2095cifs_writev_callback(struct mid_q_entry *mid)
2096{
2097 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002098 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099 unsigned int written;
2100 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002101 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002103 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002104 case MID_RESPONSE_RECEIVED:
2105 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2106 if (wdata->result != 0)
2107 break;
2108
2109 written = le16_to_cpu(smb->CountHigh);
2110 written <<= 16;
2111 written += le16_to_cpu(smb->Count);
2112 /*
2113 * Mask off high 16 bits when bytes written as returned
2114 * by the server is greater than bytes requested by the
2115 * client. OS/2 servers are known to set incorrect
2116 * CountHigh values.
2117 */
2118 if (written > wdata->bytes)
2119 written &= 0xFFFF;
2120
2121 if (written < wdata->bytes)
2122 wdata->result = -ENOSPC;
2123 else
2124 wdata->bytes = written;
2125 break;
2126 case MID_REQUEST_SUBMITTED:
2127 case MID_RETRY_NEEDED:
2128 wdata->result = -EAGAIN;
2129 break;
2130 default:
2131 wdata->result = -EIO;
2132 break;
2133 }
2134
Jeff Laytonda472fc2012-03-23 14:40:53 -04002135 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002136 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002137 add_credits(tcon->ses->server, &credits, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002138}
2139
2140/* cifs_async_writev - send an async write, and set up mid to handle result */
2141int
Steve French4a5c80d2014-02-07 20:45:12 -06002142cifs_async_writev(struct cifs_writedata *wdata,
2143 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002144{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002145 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002146 WRITE_REQ *smb = NULL;
2147 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002148 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002149 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002150 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002151
2152 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2153 wct = 14;
2154 } else {
2155 wct = 12;
2156 if (wdata->offset >> 32 > 0) {
2157 /* can not handle big offset for old srv */
2158 return -EIO;
2159 }
2160 }
2161
2162 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2163 if (rc)
2164 goto async_writev_out;
2165
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002166 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2167 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002168
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002170 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002171 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2172 if (wct == 14)
2173 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2174 smb->Reserved = 0xFFFFFFFF;
2175 smb->WriteMode = 0;
2176 smb->Remaining = 0;
2177
2178 smb->DataOffset =
2179 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2180
2181 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002182 iov[0].iov_len = 4;
2183 iov[0].iov_base = smb;
2184 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2185 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002186
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002187 rqst.rq_iov = iov;
2188 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002189 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002190 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002191 rqst.rq_npages = wdata->nr_pages;
2192 rqst.rq_pagesz = wdata->pagesz;
2193 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002194
Joe Perchesf96637b2013-05-04 22:12:25 -05002195 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2196 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002197
2198 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2199 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2200
2201 if (wct == 14) {
2202 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2203 put_bcc(wdata->bytes + 1, &smb->hdr);
2204 } else {
2205 /* wct == 12 */
2206 struct smb_com_writex_req *smbw =
2207 (struct smb_com_writex_req *)smb;
2208 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2209 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002210 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002211 }
2212
2213 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002214 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08002215 cifs_writev_callback, NULL, wdata, 0, NULL);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002216
2217 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002218 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002219 else
Steve French4a5c80d2014-02-07 20:45:12 -06002220 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002221
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002222async_writev_out:
2223 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002224 return rc;
2225}
2226
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002227int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002228CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002229 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230{
Colin Ian King136a5dc2020-05-27 13:50:31 +01002231 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002233 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002234 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002235 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002236 __u32 pid = io_parms->pid;
2237 __u16 netfid = io_parms->netfid;
2238 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002239 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002240 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002241 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002243 *nbytes = 0;
2244
Joe Perchesf96637b2013-05-04 22:12:25 -05002245 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002246
Steve French4c3130e2008-12-09 00:28:16 +00002247 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002248 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002249 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002250 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002251 if ((offset >> 32) > 0) {
2252 /* can not handle big offset for old srv */
2253 return -EIO;
2254 }
2255 }
Steve French8cc64c62005-10-03 13:49:43 -07002256 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 if (rc)
2258 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002259
2260 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2261 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2262
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 /* tcon and ses pointer are checked in smb_init */
2264 if (tcon->ses->server == NULL)
2265 return -ECONNABORTED;
2266
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002267 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 pSMB->Fid = netfid;
2269 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002270 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002271 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 pSMB->Reserved = 0xFFFFFFFF;
2273 pSMB->WriteMode = 0;
2274 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002275
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002277 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278
Steve French3e844692005-10-03 13:37:24 -07002279 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2280 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002281 /* header + 1 byte pad */
2282 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002283 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002284 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002285 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002286 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002287 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002288 pSMB->ByteCount = cpu_to_le16(count + 1);
2289 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002290 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002291 (struct smb_com_writex_req *)pSMB;
2292 pSMBW->ByteCount = cpu_to_le16(count + 5);
2293 }
Steve French3e844692005-10-03 13:37:24 -07002294 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002295 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002296 iov[0].iov_len = smb_hdr_len + 4;
2297 else /* wct == 12 pad bigger by four bytes */
2298 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002299
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002300 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2301 &rsp_iov);
2302 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002303 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002305 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002306 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002307 /* presumably this can not happen, but best to be safe */
2308 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002309 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002310 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002311 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2312 *nbytes = (*nbytes) << 16;
2313 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302314
2315 /*
2316 * Mask off high 16 bits when bytes written as returned by the
2317 * server is greater than bytes requested by the client. OS/2
2318 * servers are known to set incorrect CountHigh values.
2319 */
2320 if (*nbytes > count)
2321 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002324 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Steve French50c2f752007-07-13 00:33:32 +00002326 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 since file handle passed in no longer valid */
2328
2329 return rc;
2330}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002331
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002332int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2333 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002334 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2335{
2336 int rc = 0;
2337 LOCK_REQ *pSMB = NULL;
2338 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002339 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002340 int resp_buf_type;
2341 __u16 count;
2342
Joe Perchesf96637b2013-05-04 22:12:25 -05002343 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2344 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002345
2346 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2347 if (rc)
2348 return rc;
2349
2350 pSMB->Timeout = 0;
2351 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2352 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2353 pSMB->LockType = lock_type;
2354 pSMB->AndXCommand = 0xFF; /* none */
2355 pSMB->Fid = netfid; /* netfid stays le */
2356
2357 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2358 inc_rfc1001_len(pSMB, count);
2359 pSMB->ByteCount = cpu_to_le16(count);
2360
2361 iov[0].iov_base = (char *)pSMB;
2362 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2363 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2364 iov[1].iov_base = (char *)buf;
2365 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2366
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002367 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002368 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
2369 CIFS_NO_RSP_BUF, &rsp_iov);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002370 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002371 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002372 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002373
2374 return rc;
2375}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002378CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002379 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002381 const __u32 numLock, const __u8 lockType,
2382 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383{
2384 int rc = 0;
2385 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002386/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002388 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 __u16 count;
2390
Joe Perchesf96637b2013-05-04 22:12:25 -05002391 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2392 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002393 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 if (rc)
2396 return rc;
2397
Steve French790fe572007-07-07 19:25:05 +00002398 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002399 /* no response expected */
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002400 flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002402 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002403 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2405 } else {
2406 pSMB->Timeout = 0;
2407 }
2408
2409 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2410 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2411 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002412 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 pSMB->AndXCommand = 0xFF; /* none */
2414 pSMB->Fid = smb_file_id; /* netfid stays le */
2415
Steve French790fe572007-07-07 19:25:05 +00002416 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002417 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 /* BB where to store pid high? */
2419 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2420 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2421 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2422 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2423 count = sizeof(LOCKING_ANDX_RANGE);
2424 } else {
2425 /* oplock break */
2426 count = 0;
2427 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002428 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 pSMB->ByteCount = cpu_to_le16(count);
2430
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002431 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002432 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002433 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002434 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002435 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002436 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002437 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002438 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002439 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
Steve French50c2f752007-07-13 00:33:32 +00002441 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 since file handle passed in no longer valid */
2443 return rc;
2444}
2445
2446int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002447CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002448 const __u16 smb_file_id, const __u32 netpid,
2449 const loff_t start_offset, const __u64 len,
2450 struct file_lock *pLockData, const __u16 lock_type,
2451 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002452{
2453 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2454 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002455 struct cifs_posix_lock *parm_data;
2456 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002457 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002458 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002459 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002460 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002461 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002462 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002463
Joe Perchesf96637b2013-05-04 22:12:25 -05002464 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002465
Steve French08547b02006-02-28 22:39:25 +00002466 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2467
2468 if (rc)
2469 return rc;
2470
2471 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2472
Steve French50c2f752007-07-13 00:33:32 +00002473 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002474 pSMB->MaxSetupCount = 0;
2475 pSMB->Reserved = 0;
2476 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002477 pSMB->Reserved2 = 0;
2478 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2479 offset = param_offset + params;
2480
Steve French08547b02006-02-28 22:39:25 +00002481 count = sizeof(struct cifs_posix_lock);
2482 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002483 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002484 pSMB->SetupCount = 1;
2485 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002486 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002487 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2488 else
2489 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2490 byte_count = 3 /* pad */ + params + count;
2491 pSMB->DataCount = cpu_to_le16(count);
2492 pSMB->ParameterCount = cpu_to_le16(params);
2493 pSMB->TotalDataCount = pSMB->DataCount;
2494 pSMB->TotalParameterCount = pSMB->ParameterCount;
2495 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve Frenchd4dc2772021-07-07 14:03:54 -05002496 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
Steve French50c2f752007-07-13 00:33:32 +00002497 parm_data = (struct cifs_posix_lock *)
Steve Frenchd4dc2772021-07-07 14:03:54 -05002498 (((char *)pSMB) + offset + 4);
Steve French08547b02006-02-28 22:39:25 +00002499
2500 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002501 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002502 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002503 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002504 pSMB->Timeout = cpu_to_le32(-1);
2505 } else
2506 pSMB->Timeout = 0;
2507
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002508 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002509 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002510 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002511
2512 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002513 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002514 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2515 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002516 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002517 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002518 if (waitFlag) {
2519 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2520 (struct smb_hdr *) pSMBr, &bytes_returned);
2521 } else {
Steve French133672e2007-11-13 22:41:37 +00002522 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002523 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002524 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002525 &resp_buf_type, timeout, &rsp_iov);
2526 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002527 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002528 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002529
Steve French08547b02006-02-28 22:39:25 +00002530 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002531 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002532 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002533 /* lock structure can be returned on get */
2534 __u16 data_offset;
2535 __u16 data_count;
2536 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002537
Jeff Layton820a8032011-05-04 08:05:26 -04002538 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002539 rc = -EIO; /* bad smb */
2540 goto plk_err_exit;
2541 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002542 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2543 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002544 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002545 rc = -EIO;
2546 goto plk_err_exit;
2547 }
2548 parm_data = (struct cifs_posix_lock *)
2549 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002550 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002551 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002552 else {
2553 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002554 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002555 pLockData->fl_type = F_RDLCK;
2556 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002557 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002558 pLockData->fl_type = F_WRLCK;
2559
Steve French5443d132011-03-13 05:08:25 +00002560 pLockData->fl_start = le64_to_cpu(parm_data->start);
2561 pLockData->fl_end = pLockData->fl_start +
2562 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002563 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002564 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002565 }
Steve French50c2f752007-07-13 00:33:32 +00002566
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002567plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002568 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002569
Steve French08547b02006-02-28 22:39:25 +00002570 /* Note: On -EAGAIN error only caller can retry on handle based calls
2571 since file handle passed in no longer valid */
2572
2573 return rc;
2574}
2575
2576
2577int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002578CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579{
2580 int rc = 0;
2581 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002582 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584/* do not retry on dead session on close */
2585 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002586 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 return 0;
2588 if (rc)
2589 return rc;
2590
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002592 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002594 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002595 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002596 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002598 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002600 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 }
2602 }
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002605 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 rc = 0;
2607
2608 return rc;
2609}
2610
2611int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002612CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002613{
2614 int rc = 0;
2615 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002616 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002617
2618 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2619 if (rc)
2620 return rc;
2621
2622 pSMB->FileID = (__u16) smb_file_id;
2623 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002624 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002625 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002626 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002627 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002628 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002629
2630 return rc;
2631}
2632
2633int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002634CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002635 const char *from_name, const char *to_name,
2636 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637{
2638 int rc = 0;
2639 RENAME_REQ *pSMB = NULL;
2640 RENAME_RSP *pSMBr = NULL;
2641 int bytes_returned;
2642 int name_len, name_len2;
2643 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002644 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
Joe Perchesf96637b2013-05-04 22:12:25 -05002646 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647renameRetry:
2648 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2649 (void **) &pSMBr);
2650 if (rc)
2651 return rc;
2652
2653 pSMB->BufferFormat = 0x04;
2654 pSMB->SearchAttributes =
2655 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2656 ATTR_DIRECTORY);
2657
2658 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002659 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2660 from_name, PATH_MAX,
2661 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 name_len++; /* trailing null */
2663 name_len *= 2;
2664 pSMB->OldFileName[name_len] = 0x04; /* pad */
2665 /* protocol requires ASCII signature byte on Unicode string */
2666 pSMB->OldFileName[name_len + 1] = 0x00;
2667 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002668 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002669 to_name, PATH_MAX, cifs_sb->local_nls,
2670 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2672 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002673 } else {
2674 name_len = copy_path_name(pSMB->OldFileName, from_name);
2675 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 name_len2++; /* signature byte */
2678 }
2679
2680 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002681 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 pSMB->ByteCount = cpu_to_le16(count);
2683
2684 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2685 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002686 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002687 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002688 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 cifs_buf_release(pSMB);
2691
2692 if (rc == -EAGAIN)
2693 goto renameRetry;
2694
2695 return rc;
2696}
2697
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002698int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002699 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002700 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701{
2702 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2703 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002704 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 char *data_offset;
2706 char dummy_string[30];
2707 int rc = 0;
2708 int bytes_returned = 0;
2709 int len_of_str;
2710 __u16 params, param_offset, offset, count, byte_count;
2711
Joe Perchesf96637b2013-05-04 22:12:25 -05002712 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2714 (void **) &pSMBr);
2715 if (rc)
2716 return rc;
2717
2718 params = 6;
2719 pSMB->MaxSetupCount = 0;
2720 pSMB->Reserved = 0;
2721 pSMB->Flags = 0;
2722 pSMB->Timeout = 0;
2723 pSMB->Reserved2 = 0;
2724 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2725 offset = param_offset + params;
2726
Steve Frenchf3717932021-07-07 13:34:47 -05002727 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2728 data_offset = (char *)(pSMB) + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 rename_info = (struct set_file_rename *) data_offset;
2730 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002731 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 pSMB->SetupCount = 1;
2733 pSMB->Reserved3 = 0;
2734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2735 byte_count = 3 /* pad */ + params;
2736 pSMB->ParameterCount = cpu_to_le16(params);
2737 pSMB->TotalParameterCount = pSMB->ParameterCount;
2738 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2739 pSMB->DataOffset = cpu_to_le16(offset);
2740 /* construct random name ".cifs_tmp<inodenum><mid>" */
2741 rename_info->overwrite = cpu_to_le32(1);
2742 rename_info->root_fid = 0;
2743 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002744 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002745 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002746 len_of_str =
2747 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002748 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002750 len_of_str =
2751 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002752 target_name, PATH_MAX, nls_codepage,
2753 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 }
2755 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002756 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 byte_count += count;
2758 pSMB->DataCount = cpu_to_le16(count);
2759 pSMB->TotalDataCount = pSMB->DataCount;
2760 pSMB->Fid = netfid;
2761 pSMB->InformationLevel =
2762 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2763 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002764 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 pSMB->ByteCount = cpu_to_le16(byte_count);
2766 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002767 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002768 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002769 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002770 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2771 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002772
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 cifs_buf_release(pSMB);
2774
2775 /* Note: On -EAGAIN error only caller can retry on handle based calls
2776 since file handle passed in no longer valid */
2777
2778 return rc;
2779}
2780
2781int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002782CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2783 const char *fromName, const __u16 target_tid, const char *toName,
2784 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785{
2786 int rc = 0;
2787 COPY_REQ *pSMB = NULL;
2788 COPY_RSP *pSMBr = NULL;
2789 int bytes_returned;
2790 int name_len, name_len2;
2791 __u16 count;
2792
Joe Perchesf96637b2013-05-04 22:12:25 -05002793 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794copyRetry:
2795 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2796 (void **) &pSMBr);
2797 if (rc)
2798 return rc;
2799
2800 pSMB->BufferFormat = 0x04;
2801 pSMB->Tid2 = target_tid;
2802
2803 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2804
2805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002806 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2807 fromName, PATH_MAX, nls_codepage,
2808 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 name_len++; /* trailing null */
2810 name_len *= 2;
2811 pSMB->OldFileName[name_len] = 0x04; /* pad */
2812 /* protocol requires ASCII signature byte on Unicode string */
2813 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002814 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002815 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2816 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2818 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002819 } else {
2820 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002822 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 name_len2++; /* signature byte */
2824 }
2825
2826 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002827 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 pSMB->ByteCount = cpu_to_le16(count);
2829
2830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2832 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002833 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2834 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 }
Steve French0d817bc2008-05-22 02:02:03 +00002836 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837
2838 if (rc == -EAGAIN)
2839 goto copyRetry;
2840
2841 return rc;
2842}
2843
2844int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002845CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002847 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848{
2849 TRANSACTION2_SPI_REQ *pSMB = NULL;
2850 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2851 char *data_offset;
2852 int name_len;
2853 int name_len_target;
2854 int rc = 0;
2855 int bytes_returned = 0;
2856 __u16 params, param_offset, offset, byte_count;
2857
Joe Perchesf96637b2013-05-04 22:12:25 -05002858 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859createSymLinkRetry:
2860 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2861 (void **) &pSMBr);
2862 if (rc)
2863 return rc;
2864
2865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2866 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002867 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2868 /* find define for this maxpathcomponent */
2869 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 name_len++; /* trailing null */
2871 name_len *= 2;
2872
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002873 } else {
2874 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 }
2876 params = 6 + name_len;
2877 pSMB->MaxSetupCount = 0;
2878 pSMB->Reserved = 0;
2879 pSMB->Flags = 0;
2880 pSMB->Timeout = 0;
2881 pSMB->Reserved2 = 0;
2882 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002883 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 offset = param_offset + params;
2885
Steve Frenchded2d992021-07-01 20:44:27 -05002886 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2887 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2889 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002890 cifsConvertToUTF16((__le16 *) data_offset, toName,
2891 /* find define for this maxpathcomponent */
2892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 name_len_target++; /* trailing null */
2894 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002895 } else {
2896 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 }
2898
2899 pSMB->MaxParameterCount = cpu_to_le16(2);
2900 /* BB find exact max on data count below from sess */
2901 pSMB->MaxDataCount = cpu_to_le16(1000);
2902 pSMB->SetupCount = 1;
2903 pSMB->Reserved3 = 0;
2904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2905 byte_count = 3 /* pad */ + params + name_len_target;
2906 pSMB->DataCount = cpu_to_le16(name_len_target);
2907 pSMB->ParameterCount = cpu_to_le16(params);
2908 pSMB->TotalDataCount = pSMB->DataCount;
2909 pSMB->TotalParameterCount = pSMB->ParameterCount;
2910 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2911 pSMB->DataOffset = cpu_to_le16(offset);
2912 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2913 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002914 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 pSMB->ByteCount = cpu_to_le16(byte_count);
2916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002918 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002919 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002920 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2921 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
Steve French0d817bc2008-05-22 02:02:03 +00002923 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
2925 if (rc == -EAGAIN)
2926 goto createSymLinkRetry;
2927
2928 return rc;
2929}
2930
2931int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002932CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002934 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935{
2936 TRANSACTION2_SPI_REQ *pSMB = NULL;
2937 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2938 char *data_offset;
2939 int name_len;
2940 int name_len_target;
2941 int rc = 0;
2942 int bytes_returned = 0;
2943 __u16 params, param_offset, offset, byte_count;
2944
Joe Perchesf96637b2013-05-04 22:12:25 -05002945 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946createHardLinkRetry:
2947 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2948 (void **) &pSMBr);
2949 if (rc)
2950 return rc;
2951
2952 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002953 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2954 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 name_len++; /* trailing null */
2956 name_len *= 2;
2957
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002958 } else {
2959 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 }
2961 params = 6 + name_len;
2962 pSMB->MaxSetupCount = 0;
2963 pSMB->Reserved = 0;
2964 pSMB->Flags = 0;
2965 pSMB->Timeout = 0;
2966 pSMB->Reserved2 = 0;
2967 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002968 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 offset = param_offset + params;
2970
Steve French819f9162021-07-01 17:46:23 -05002971 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2972 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2974 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002975 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2976 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 name_len_target++; /* trailing null */
2978 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002979 } else {
2980 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 }
2982
2983 pSMB->MaxParameterCount = cpu_to_le16(2);
2984 /* BB find exact max on data count below from sess*/
2985 pSMB->MaxDataCount = cpu_to_le16(1000);
2986 pSMB->SetupCount = 1;
2987 pSMB->Reserved3 = 0;
2988 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2989 byte_count = 3 /* pad */ + params + name_len_target;
2990 pSMB->ParameterCount = cpu_to_le16(params);
2991 pSMB->TotalParameterCount = pSMB->ParameterCount;
2992 pSMB->DataCount = cpu_to_le16(name_len_target);
2993 pSMB->TotalDataCount = pSMB->DataCount;
2994 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2995 pSMB->DataOffset = cpu_to_le16(offset);
2996 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2997 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002998 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 pSMB->ByteCount = cpu_to_le16(byte_count);
3000 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3001 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003002 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003003 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003004 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3005 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006
3007 cifs_buf_release(pSMB);
3008 if (rc == -EAGAIN)
3009 goto createHardLinkRetry;
3010
3011 return rc;
3012}
3013
3014int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003015CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003016 const char *from_name, const char *to_name,
3017 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018{
3019 int rc = 0;
3020 NT_RENAME_REQ *pSMB = NULL;
3021 RENAME_RSP *pSMBr = NULL;
3022 int bytes_returned;
3023 int name_len, name_len2;
3024 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003025 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Joe Perchesf96637b2013-05-04 22:12:25 -05003027 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028winCreateHardLinkRetry:
3029
3030 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3031 (void **) &pSMBr);
3032 if (rc)
3033 return rc;
3034
3035 pSMB->SearchAttributes =
3036 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3037 ATTR_DIRECTORY);
3038 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3039 pSMB->ClusterCount = 0;
3040
3041 pSMB->BufferFormat = 0x04;
3042
3043 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3044 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003045 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3046 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 name_len++; /* trailing null */
3048 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003049
3050 /* protocol specifies ASCII buffer format (0x04) for unicode */
3051 pSMB->OldFileName[name_len] = 0x04;
3052 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003054 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003055 to_name, PATH_MAX, cifs_sb->local_nls,
3056 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3058 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003059 } else {
3060 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003062 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 name_len2++; /* signature byte */
3064 }
3065
3066 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003067 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 pSMB->ByteCount = cpu_to_le16(count);
3069
3070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003072 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003073 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003074 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003075
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 cifs_buf_release(pSMB);
3077 if (rc == -EAGAIN)
3078 goto winCreateHardLinkRetry;
3079
3080 return rc;
3081}
3082
3083int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003084CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003085 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003086 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087{
3088/* SMB_QUERY_FILE_UNIX_LINK */
3089 TRANSACTION2_QPI_REQ *pSMB = NULL;
3090 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3091 int rc = 0;
3092 int bytes_returned;
3093 int name_len;
3094 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003095 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Joe Perchesf96637b2013-05-04 22:12:25 -05003097 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
3099querySymLinkRetry:
3100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3101 (void **) &pSMBr);
3102 if (rc)
3103 return rc;
3104
3105 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3106 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003107 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3108 searchName, PATH_MAX, nls_codepage,
3109 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 name_len++; /* trailing null */
3111 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003112 } else {
3113 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 }
3115
3116 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3117 pSMB->TotalDataCount = 0;
3118 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003119 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 pSMB->MaxSetupCount = 0;
3121 pSMB->Reserved = 0;
3122 pSMB->Flags = 0;
3123 pSMB->Timeout = 0;
3124 pSMB->Reserved2 = 0;
3125 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003126 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 pSMB->DataCount = 0;
3128 pSMB->DataOffset = 0;
3129 pSMB->SetupCount = 1;
3130 pSMB->Reserved3 = 0;
3131 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3132 byte_count = params + 1 /* pad */ ;
3133 pSMB->TotalParameterCount = cpu_to_le16(params);
3134 pSMB->ParameterCount = pSMB->TotalParameterCount;
3135 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3136 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003137 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 pSMB->ByteCount = cpu_to_le16(byte_count);
3139
3140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3142 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003143 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 } else {
3145 /* decode response */
3146
3147 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003149 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003150 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003152 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003153 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154
Jeff Layton460b9692009-04-30 07:17:56 -04003155 data_start = ((char *) &pSMBr->hdr.Protocol) +
3156 le16_to_cpu(pSMBr->t2.DataOffset);
3157
Steve French0e0d2cf2009-05-01 05:27:32 +00003158 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3159 is_unicode = true;
3160 else
3161 is_unicode = false;
3162
Steve French737b7582005-04-28 22:41:06 -07003163 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003164 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3165 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003166 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003167 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 }
3169 }
3170 cifs_buf_release(pSMB);
3171 if (rc == -EAGAIN)
3172 goto querySymLinkRetry;
3173 return rc;
3174}
3175
Steve Frenchc52a95542011-02-24 06:16:22 +00003176/*
3177 * Recent Windows versions now create symlinks more frequently
3178 * and they use the "reparse point" mechanism below. We can of course
3179 * do symlinks nicely to Samba and other servers which support the
3180 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3181 * "MF" symlinks optionally, but for recent Windows we really need to
3182 * reenable the code below and fix the cifs_symlink callers to handle this.
3183 * In the interim this code has been moved to its own config option so
3184 * it is not compiled in by default until callers fixed up and more tested.
3185 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003187CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3188 __u16 fid, char **symlinkinfo,
3189 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190{
3191 int rc = 0;
3192 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003193 struct smb_com_transaction_ioctl_req *pSMB;
3194 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003195 bool is_unicode;
3196 unsigned int sub_len;
3197 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003198 struct reparse_symlink_data *reparse_buf;
3199 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003200 __u32 data_offset, data_count;
3201 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003203 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return rc;
3208
3209 pSMB->TotalParameterCount = 0 ;
3210 pSMB->TotalDataCount = 0;
3211 pSMB->MaxParameterCount = cpu_to_le32(2);
3212 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003213 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 pSMB->MaxSetupCount = 4;
3215 pSMB->Reserved = 0;
3216 pSMB->ParameterOffset = 0;
3217 pSMB->DataCount = 0;
3218 pSMB->DataOffset = 0;
3219 pSMB->SetupCount = 4;
3220 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3221 pSMB->ParameterCount = pSMB->TotalParameterCount;
3222 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3223 pSMB->IsFsctl = 1; /* FSCTL */
3224 pSMB->IsRootFlag = 0;
3225 pSMB->Fid = fid; /* file handle always le */
3226 pSMB->ByteCount = 0;
3227
3228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3229 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3230 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003231 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003232 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 }
Steve French989c7e52009-05-02 05:32:20 +00003234
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003235 data_offset = le32_to_cpu(pSMBr->DataOffset);
3236 data_count = le32_to_cpu(pSMBr->DataCount);
3237 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3238 /* BB also check enough total bytes returned */
3239 rc = -EIO; /* bad smb */
3240 goto qreparse_out;
3241 }
3242 if (!data_count || (data_count > 2048)) {
3243 rc = -EIO;
3244 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3245 goto qreparse_out;
3246 }
3247 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003248 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003249 ((char *)&pSMBr->hdr.Protocol + data_offset);
3250 if ((char *)reparse_buf >= end_of_smb) {
3251 rc = -EIO;
3252 goto qreparse_out;
3253 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003254 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3255 cifs_dbg(FYI, "NFS style reparse tag\n");
3256 posix_buf = (struct reparse_posix_data *)reparse_buf;
3257
3258 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3259 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3260 le64_to_cpu(posix_buf->InodeType));
3261 rc = -EOPNOTSUPP;
3262 goto qreparse_out;
3263 }
3264 is_unicode = true;
3265 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3266 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3267 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3268 rc = -EIO;
3269 goto qreparse_out;
3270 }
3271 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3272 sub_len, is_unicode, nls_codepage);
3273 goto qreparse_out;
3274 } else if (reparse_buf->ReparseTag !=
3275 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3276 rc = -EOPNOTSUPP;
3277 goto qreparse_out;
3278 }
3279
3280 /* Reparse tag is NTFS symlink */
3281 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3282 reparse_buf->PathBuffer;
3283 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3284 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003285 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3286 rc = -EIO;
3287 goto qreparse_out;
3288 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003289 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3290 is_unicode = true;
3291 else
3292 is_unicode = false;
3293
3294 /* BB FIXME investigate remapping reserved chars here */
3295 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3296 nls_codepage);
3297 if (!*symlinkinfo)
3298 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003300 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003302 /*
3303 * Note: On -EAGAIN error only caller can retry on handle based calls
3304 * since file handle passed in no longer valid.
3305 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 return rc;
3307}
3308
Steve Frenchc7f508a2013-10-14 15:27:32 -05003309int
3310CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3311 __u16 fid)
3312{
3313 int rc = 0;
3314 int bytes_returned;
3315 struct smb_com_transaction_compr_ioctl_req *pSMB;
3316 struct smb_com_transaction_ioctl_rsp *pSMBr;
3317
3318 cifs_dbg(FYI, "Set compression for %u\n", fid);
3319 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3320 (void **) &pSMBr);
3321 if (rc)
3322 return rc;
3323
3324 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3325
3326 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003327 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003328 pSMB->MaxParameterCount = 0;
3329 pSMB->MaxDataCount = 0;
3330 pSMB->MaxSetupCount = 4;
3331 pSMB->Reserved = 0;
3332 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003333 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003334 pSMB->DataOffset =
3335 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3336 compression_state) - 4); /* 84 */
3337 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003338 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003339 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003340 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003341 pSMB->IsFsctl = 1; /* FSCTL */
3342 pSMB->IsRootFlag = 0;
3343 pSMB->Fid = fid; /* file handle always le */
3344 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003345 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003346 inc_rfc1001_len(pSMB, 5);
3347
3348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3350 if (rc)
3351 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3352
3353 cifs_buf_release(pSMB);
3354
3355 /*
3356 * Note: On -EAGAIN error only caller can retry on handle based calls
3357 * since file handle passed in no longer valid.
3358 */
3359 return rc;
3360}
3361
3362
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363#ifdef CONFIG_CIFS_POSIX
3364
3365/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003366static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003367 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368{
3369 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003370 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3371 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3372 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003373/*
3374 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3375 ace->e_perm, ace->e_tag, ace->e_id);
3376*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
3378 return;
3379}
3380
3381/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003382static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3383 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384{
3385 int size = 0;
3386 int i;
3387 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003388 struct cifs_posix_ace *pACE;
3389 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003390 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391
3392 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3393 return -EOPNOTSUPP;
3394
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003395 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 count = le16_to_cpu(cifs_acl->access_entry_count);
3397 pACE = &cifs_acl->ace_array[0];
3398 size = sizeof(struct cifs_posix_acl);
3399 size += sizeof(struct cifs_posix_ace) * count;
3400 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003401 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003402 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3403 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 return -EINVAL;
3405 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003406 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 count = le16_to_cpu(cifs_acl->access_entry_count);
3408 size = sizeof(struct cifs_posix_acl);
3409 size += sizeof(struct cifs_posix_ace) * count;
3410/* skip past access ACEs to get to default ACEs */
3411 pACE = &cifs_acl->ace_array[count];
3412 count = le16_to_cpu(cifs_acl->default_entry_count);
3413 size += sizeof(struct cifs_posix_ace) * count;
3414 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003415 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 return -EINVAL;
3417 } else {
3418 /* illegal type */
3419 return -EINVAL;
3420 }
3421
3422 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003423 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003424 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003425 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 return -ERANGE;
3427 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003428 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3429
Steve Frenchff7feac2005-11-15 16:45:16 -08003430 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003431 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003432 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003433 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 }
3435 }
3436 return size;
3437}
3438
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303439static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003440 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441{
Steve Frenchff7feac2005-11-15 16:45:16 -08003442 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3443 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003445 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 /* Probably no need to le convert -1 on any arch but can not hurt */
3447 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003448 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003449 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003450/*
3451 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3452 ace->e_perm, ace->e_tag, ace->e_id);
3453*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454}
3455
3456/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003457static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3458 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459{
3460 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003461 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003462 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003463 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 int count;
3465 int i;
3466
Steve French790fe572007-07-07 19:25:05 +00003467 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 return 0;
3469
3470 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003471 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3472 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003473 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003474 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3475 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 return 0;
3477 }
3478 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003479 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003480 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003481 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003482 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003483 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003484 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003485 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003486 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 return 0;
3488 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303489 for (i = 0; i < count; i++)
3490 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003491 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3493 rc += sizeof(struct cifs_posix_acl);
3494 /* BB add check to make sure ACL does not overflow SMB */
3495 }
3496 return rc;
3497}
3498
3499int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003500CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003501 const unsigned char *searchName,
3502 char *acl_inf, const int buflen, const int acl_type,
3503 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504{
3505/* SMB_QUERY_POSIX_ACL */
3506 TRANSACTION2_QPI_REQ *pSMB = NULL;
3507 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3508 int rc = 0;
3509 int bytes_returned;
3510 int name_len;
3511 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003512
Joe Perchesf96637b2013-05-04 22:12:25 -05003513 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
3515queryAclRetry:
3516 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3517 (void **) &pSMBr);
3518 if (rc)
3519 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003520
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3522 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003523 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3524 searchName, PATH_MAX, nls_codepage,
3525 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 name_len++; /* trailing null */
3527 name_len *= 2;
3528 pSMB->FileName[name_len] = 0;
3529 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003530 } else {
3531 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 }
3533
3534 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3535 pSMB->TotalDataCount = 0;
3536 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003537 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 pSMB->MaxDataCount = cpu_to_le16(4000);
3539 pSMB->MaxSetupCount = 0;
3540 pSMB->Reserved = 0;
3541 pSMB->Flags = 0;
3542 pSMB->Timeout = 0;
3543 pSMB->Reserved2 = 0;
3544 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003545 offsetof(struct smb_com_transaction2_qpi_req,
3546 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 pSMB->DataCount = 0;
3548 pSMB->DataOffset = 0;
3549 pSMB->SetupCount = 1;
3550 pSMB->Reserved3 = 0;
3551 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3552 byte_count = params + 1 /* pad */ ;
3553 pSMB->TotalParameterCount = cpu_to_le16(params);
3554 pSMB->ParameterCount = pSMB->TotalParameterCount;
3555 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3556 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003557 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 pSMB->ByteCount = cpu_to_le16(byte_count);
3559
3560 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3561 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003562 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003564 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 } else {
3566 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003567
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003570 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 rc = -EIO; /* bad smb */
3572 else {
3573 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3574 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3575 rc = cifs_copy_posix_acl(acl_inf,
3576 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003577 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 }
3579 }
3580 cifs_buf_release(pSMB);
3581 if (rc == -EAGAIN)
3582 goto queryAclRetry;
3583 return rc;
3584}
3585
3586int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003587CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003588 const unsigned char *fileName,
3589 const char *local_acl, const int buflen,
3590 const int acl_type,
3591 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592{
3593 struct smb_com_transaction2_spi_req *pSMB = NULL;
3594 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3595 char *parm_data;
3596 int name_len;
3597 int rc = 0;
3598 int bytes_returned = 0;
3599 __u16 params, byte_count, data_count, param_offset, offset;
3600
Joe Perchesf96637b2013-05-04 22:12:25 -05003601 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602setAclRetry:
3603 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003604 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 if (rc)
3606 return rc;
3607 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3608 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003609 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3610 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 name_len++; /* trailing null */
3612 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003613 } else {
3614 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 }
3616 params = 6 + name_len;
3617 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003618 /* BB find max SMB size from sess */
3619 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 pSMB->MaxSetupCount = 0;
3621 pSMB->Reserved = 0;
3622 pSMB->Flags = 0;
3623 pSMB->Timeout = 0;
3624 pSMB->Reserved2 = 0;
3625 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003626 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 offset = param_offset + params;
3628 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3629 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3630
3631 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003632 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633
Steve French790fe572007-07-07 19:25:05 +00003634 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 rc = -EOPNOTSUPP;
3636 goto setACLerrorExit;
3637 }
3638 pSMB->DataOffset = cpu_to_le16(offset);
3639 pSMB->SetupCount = 1;
3640 pSMB->Reserved3 = 0;
3641 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3642 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3643 byte_count = 3 /* pad */ + params + data_count;
3644 pSMB->DataCount = cpu_to_le16(data_count);
3645 pSMB->TotalDataCount = pSMB->DataCount;
3646 pSMB->ParameterCount = cpu_to_le16(params);
3647 pSMB->TotalParameterCount = pSMB->ParameterCount;
3648 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003649 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 pSMB->ByteCount = cpu_to_le16(byte_count);
3651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003653 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003654 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655
3656setACLerrorExit:
3657 cifs_buf_release(pSMB);
3658 if (rc == -EAGAIN)
3659 goto setAclRetry;
3660 return rc;
3661}
3662
Steve Frenchf654bac2005-04-28 22:41:04 -07003663/* BB fix tabs in this function FIXME BB */
3664int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003665CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003666 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003667{
Steve French50c2f752007-07-13 00:33:32 +00003668 int rc = 0;
3669 struct smb_t2_qfi_req *pSMB = NULL;
3670 struct smb_t2_qfi_rsp *pSMBr = NULL;
3671 int bytes_returned;
3672 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003673
Joe Perchesf96637b2013-05-04 22:12:25 -05003674 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003675 if (tcon == NULL)
3676 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003677
3678GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003679 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3680 (void **) &pSMBr);
3681 if (rc)
3682 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003683
Steve Frenchad7a2922008-02-07 23:25:02 +00003684 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003685 pSMB->t2.TotalDataCount = 0;
3686 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3687 /* BB find exact max data count below from sess structure BB */
3688 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3689 pSMB->t2.MaxSetupCount = 0;
3690 pSMB->t2.Reserved = 0;
3691 pSMB->t2.Flags = 0;
3692 pSMB->t2.Timeout = 0;
3693 pSMB->t2.Reserved2 = 0;
3694 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3695 Fid) - 4);
3696 pSMB->t2.DataCount = 0;
3697 pSMB->t2.DataOffset = 0;
3698 pSMB->t2.SetupCount = 1;
3699 pSMB->t2.Reserved3 = 0;
3700 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3701 byte_count = params + 1 /* pad */ ;
3702 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3703 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3704 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3705 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003706 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003707 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003708 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003709
Steve French790fe572007-07-07 19:25:05 +00003710 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3711 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3712 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003713 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003714 } else {
3715 /* decode response */
3716 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003717 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003718 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003719 /* If rc should we check for EOPNOSUPP and
3720 disable the srvino flag? or in caller? */
3721 rc = -EIO; /* bad smb */
3722 else {
3723 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3724 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3725 struct file_chattr_info *pfinfo;
3726 /* BB Do we need a cast or hash here ? */
3727 if (count != 16) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003728 cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003729 rc = -EIO;
3730 goto GetExtAttrOut;
3731 }
3732 pfinfo = (struct file_chattr_info *)
3733 (data_offset + (char *) &pSMBr->hdr.Protocol);
3734 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003735 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003736 }
3737 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003738GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003739 cifs_buf_release(pSMB);
3740 if (rc == -EAGAIN)
3741 goto GetExtAttrRetry;
3742 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003743}
3744
Steve Frenchf654bac2005-04-28 22:41:04 -07003745#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
Jeff Layton79df1ba2010-12-06 12:52:08 -05003747/*
3748 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3749 * all NT TRANSACTS that we init here have total parm and data under about 400
3750 * bytes (to fit in small cifs buffer size), which is the case so far, it
3751 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3752 * returned setup area) and MaxParameterCount (returned parms size) must be set
3753 * by caller
3754 */
3755static int
3756smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003757 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003758 void **ret_buf)
3759{
3760 int rc;
3761 __u32 temp_offset;
3762 struct smb_com_ntransact_req *pSMB;
3763
3764 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3765 (void **)&pSMB);
3766 if (rc)
3767 return rc;
3768 *ret_buf = (void *)pSMB;
3769 pSMB->Reserved = 0;
3770 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3771 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003772 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003773 pSMB->ParameterCount = pSMB->TotalParameterCount;
3774 pSMB->DataCount = pSMB->TotalDataCount;
3775 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3776 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3777 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3778 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3779 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3780 pSMB->SubCommand = cpu_to_le16(sub_command);
3781 return 0;
3782}
3783
3784static int
3785validate_ntransact(char *buf, char **ppparm, char **ppdata,
3786 __u32 *pparmlen, __u32 *pdatalen)
3787{
3788 char *end_of_smb;
3789 __u32 data_count, data_offset, parm_count, parm_offset;
3790 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003791 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003792
3793 *pdatalen = 0;
3794 *pparmlen = 0;
3795
3796 if (buf == NULL)
3797 return -EINVAL;
3798
3799 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3800
Jeff Layton820a8032011-05-04 08:05:26 -04003801 bcc = get_bcc(&pSMBr->hdr);
3802 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003803 (char *)&pSMBr->ByteCount;
3804
3805 data_offset = le32_to_cpu(pSMBr->DataOffset);
3806 data_count = le32_to_cpu(pSMBr->DataCount);
3807 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3808 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3809
3810 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3811 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3812
3813 /* should we also check that parm and data areas do not overlap? */
3814 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003815 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003816 return -EINVAL;
3817 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003818 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003819 return -EINVAL;
3820 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003821 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003822 return -EINVAL;
3823 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003824 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3825 *ppdata, data_count, (data_count + *ppdata),
3826 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003827 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003828 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003829 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003830 return -EINVAL;
3831 }
3832 *pdatalen = data_count;
3833 *pparmlen = parm_count;
3834 return 0;
3835}
3836
Steve French0a4b92c2006-01-12 15:44:21 -08003837/* Get Security Descriptor (by handle) from remote server for a file or dir */
3838int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003839CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003840 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003841{
3842 int rc = 0;
3843 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003844 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003845 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003846 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003847
Joe Perchesf96637b2013-05-04 22:12:25 -05003848 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003849
Steve French630f3f0c2007-10-25 21:17:17 +00003850 *pbuflen = 0;
3851 *acl_inf = NULL;
3852
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003853 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003854 8 /* parm len */, tcon, (void **) &pSMB);
3855 if (rc)
3856 return rc;
3857
3858 pSMB->MaxParameterCount = cpu_to_le32(4);
3859 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3860 pSMB->MaxSetupCount = 0;
3861 pSMB->Fid = fid; /* file handle always le */
3862 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3863 CIFS_ACL_DACL);
3864 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003865 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003866 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003867 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003868
Steve Frencha761ac52007-10-18 21:45:27 +00003869 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003870 0, &rsp_iov);
3871 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003872 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003873 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003874 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003875 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003876 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003877 __u32 parm_len;
3878 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003879 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003880 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003881
3882/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003883 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003884 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003885 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003886 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003887 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003888
Joe Perchesf96637b2013-05-04 22:12:25 -05003889 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3890 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003891
3892 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3893 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003894 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003895 goto qsec_out;
3896 }
3897
3898/* BB check that data area is minimum length and as big as acl_len */
3899
Steve Frenchaf6f4612007-10-16 18:40:37 +00003900 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003901 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003902 cifs_dbg(VFS, "acl length %d does not match %d\n",
3903 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003904 if (*pbuflen > acl_len)
3905 *pbuflen = acl_len;
3906 }
Steve French0a4b92c2006-01-12 15:44:21 -08003907
Steve French630f3f0c2007-10-25 21:17:17 +00003908 /* check if buffer is big enough for the acl
3909 header followed by the smallest SID */
3910 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3911 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003912 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003913 rc = -EINVAL;
3914 *pbuflen = 0;
3915 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003916 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003917 if (*acl_inf == NULL) {
3918 *pbuflen = 0;
3919 rc = -ENOMEM;
3920 }
Steve French630f3f0c2007-10-25 21:17:17 +00003921 }
Steve French0a4b92c2006-01-12 15:44:21 -08003922 }
3923qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003924 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003925 return rc;
3926}
Steve French97837582007-12-31 07:47:21 +00003927
3928int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003929CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003930 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003931{
3932 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3933 int rc = 0;
3934 int bytes_returned = 0;
3935 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003936 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003937
3938setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003939 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003940 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003941 return rc;
Steve French97837582007-12-31 07:47:21 +00003942
3943 pSMB->MaxSetupCount = 0;
3944 pSMB->Reserved = 0;
3945
3946 param_count = 8;
3947 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3948 data_count = acllen;
3949 data_offset = param_offset + param_count;
3950 byte_count = 3 /* pad */ + param_count;
3951
3952 pSMB->DataCount = cpu_to_le32(data_count);
3953 pSMB->TotalDataCount = pSMB->DataCount;
3954 pSMB->MaxParameterCount = cpu_to_le32(4);
3955 pSMB->MaxDataCount = cpu_to_le32(16384);
3956 pSMB->ParameterCount = cpu_to_le32(param_count);
3957 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3958 pSMB->TotalParameterCount = pSMB->ParameterCount;
3959 pSMB->DataOffset = cpu_to_le32(data_offset);
3960 pSMB->SetupCount = 0;
3961 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3962 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3963
3964 pSMB->Fid = fid; /* file handle always le */
3965 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003966 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003967
3968 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003969 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3970 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003971 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003972 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003973 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003974
3975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3977
Joe Perchesf96637b2013-05-04 22:12:25 -05003978 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3979 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003980 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003981 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003982 cifs_buf_release(pSMB);
3983
3984 if (rc == -EAGAIN)
3985 goto setCifsAclRetry;
3986
3987 return (rc);
3988}
3989
Steve French0a4b92c2006-01-12 15:44:21 -08003990
Steve French6b8edfe2005-08-23 20:26:03 -07003991/* Legacy Query Path Information call for lookup to old servers such
3992 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003993int
3994SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3995 const char *search_name, FILE_ALL_INFO *data,
3996 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003997{
Steve Frenchad7a2922008-02-07 23:25:02 +00003998 QUERY_INFORMATION_REQ *pSMB;
3999 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004000 int rc = 0;
4001 int bytes_returned;
4002 int name_len;
4003
Joe Perchesf96637b2013-05-04 22:12:25 -05004004 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004005QInfRetry:
4006 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004007 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004008 if (rc)
4009 return rc;
4010
4011 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4012 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004013 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004014 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004015 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004016 name_len++; /* trailing null */
4017 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004018 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004019 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004020 }
4021 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004022 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004023 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004024 pSMB->ByteCount = cpu_to_le16(name_len);
4025
4026 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004027 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004028 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004029 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004030 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004031 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004032 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004033
4034 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004035 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004036 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004037 ts.tv_nsec = 0;
4038 ts.tv_sec = time;
4039 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004040 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4041 data->LastWriteTime = data->ChangeTime;
4042 data->LastAccessTime = 0;
4043 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004044 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004045 data->EndOfFile = data->AllocationSize;
4046 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004047 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004048 } else
4049 rc = -EIO; /* bad buffer passed in */
4050
4051 cifs_buf_release(pSMB);
4052
4053 if (rc == -EAGAIN)
4054 goto QInfRetry;
4055
4056 return rc;
4057}
4058
Jeff Laytonbcd53572010-02-12 07:44:16 -05004059int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004060CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004061 u16 netfid, FILE_ALL_INFO *pFindData)
4062{
4063 struct smb_t2_qfi_req *pSMB = NULL;
4064 struct smb_t2_qfi_rsp *pSMBr = NULL;
4065 int rc = 0;
4066 int bytes_returned;
4067 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004068
Jeff Laytonbcd53572010-02-12 07:44:16 -05004069QFileInfoRetry:
4070 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4071 (void **) &pSMBr);
4072 if (rc)
4073 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004074
Jeff Laytonbcd53572010-02-12 07:44:16 -05004075 params = 2 /* level */ + 2 /* fid */;
4076 pSMB->t2.TotalDataCount = 0;
4077 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4078 /* BB find exact max data count below from sess structure BB */
4079 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4080 pSMB->t2.MaxSetupCount = 0;
4081 pSMB->t2.Reserved = 0;
4082 pSMB->t2.Flags = 0;
4083 pSMB->t2.Timeout = 0;
4084 pSMB->t2.Reserved2 = 0;
4085 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4086 Fid) - 4);
4087 pSMB->t2.DataCount = 0;
4088 pSMB->t2.DataOffset = 0;
4089 pSMB->t2.SetupCount = 1;
4090 pSMB->t2.Reserved3 = 0;
4091 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4092 byte_count = params + 1 /* pad */ ;
4093 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4094 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4095 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4096 pSMB->Pad = 0;
4097 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004098 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004099 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004100
4101 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4102 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4103 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004104 cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004105 } else { /* decode response */
4106 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4107
4108 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4109 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004110 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004111 rc = -EIO; /* bad smb */
4112 else if (pFindData) {
4113 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4114 memcpy((char *) pFindData,
4115 (char *) &pSMBr->hdr.Protocol +
4116 data_offset, sizeof(FILE_ALL_INFO));
4117 } else
4118 rc = -ENOMEM;
4119 }
4120 cifs_buf_release(pSMB);
4121 if (rc == -EAGAIN)
4122 goto QFileInfoRetry;
4123
4124 return rc;
4125}
Steve French6b8edfe2005-08-23 20:26:03 -07004126
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004128CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004129 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004130 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004131 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004133 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 TRANSACTION2_QPI_REQ *pSMB = NULL;
4135 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4136 int rc = 0;
4137 int bytes_returned;
4138 int name_len;
4139 __u16 params, byte_count;
4140
Joe Perchesf96637b2013-05-04 22:12:25 -05004141 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142QPathInfoRetry:
4143 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4144 (void **) &pSMBr);
4145 if (rc)
4146 return rc;
4147
4148 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4149 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004150 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004151 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 name_len++; /* trailing null */
4153 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004154 } else {
4155 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 }
4157
Steve French50c2f752007-07-13 00:33:32 +00004158 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 pSMB->TotalDataCount = 0;
4160 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004161 /* BB find exact max SMB PDU from sess structure BB */
4162 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 pSMB->MaxSetupCount = 0;
4164 pSMB->Reserved = 0;
4165 pSMB->Flags = 0;
4166 pSMB->Timeout = 0;
4167 pSMB->Reserved2 = 0;
4168 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004169 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 pSMB->DataCount = 0;
4171 pSMB->DataOffset = 0;
4172 pSMB->SetupCount = 1;
4173 pSMB->Reserved3 = 0;
4174 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4175 byte_count = params + 1 /* pad */ ;
4176 pSMB->TotalParameterCount = cpu_to_le16(params);
4177 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004178 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004179 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4180 else
4181 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004183 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 pSMB->ByteCount = cpu_to_le16(byte_count);
4185
4186 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4187 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4188 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004189 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 } else { /* decode response */
4191 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4192
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004193 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4194 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004195 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004197 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004198 rc = -EIO; /* 24 or 26 expected but we do not read
4199 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004200 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004201 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004203
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004204 /*
4205 * On legacy responses we do not read the last field,
4206 * EAsize, fortunately since it varies by subdialect and
4207 * also note it differs on Set vs Get, ie two bytes or 4
4208 * bytes depending but we don't care here.
4209 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004210 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004211 size = sizeof(FILE_INFO_STANDARD);
4212 else
4213 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004214 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004215 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 } else
4217 rc = -ENOMEM;
4218 }
4219 cifs_buf_release(pSMB);
4220 if (rc == -EAGAIN)
4221 goto QPathInfoRetry;
4222
4223 return rc;
4224}
4225
4226int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004227CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004228 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4229{
4230 struct smb_t2_qfi_req *pSMB = NULL;
4231 struct smb_t2_qfi_rsp *pSMBr = NULL;
4232 int rc = 0;
4233 int bytes_returned;
4234 __u16 params, byte_count;
4235
4236UnixQFileInfoRetry:
4237 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4238 (void **) &pSMBr);
4239 if (rc)
4240 return rc;
4241
4242 params = 2 /* level */ + 2 /* fid */;
4243 pSMB->t2.TotalDataCount = 0;
4244 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4245 /* BB find exact max data count below from sess structure BB */
4246 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4247 pSMB->t2.MaxSetupCount = 0;
4248 pSMB->t2.Reserved = 0;
4249 pSMB->t2.Flags = 0;
4250 pSMB->t2.Timeout = 0;
4251 pSMB->t2.Reserved2 = 0;
4252 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4253 Fid) - 4);
4254 pSMB->t2.DataCount = 0;
4255 pSMB->t2.DataOffset = 0;
4256 pSMB->t2.SetupCount = 1;
4257 pSMB->t2.Reserved3 = 0;
4258 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4259 byte_count = params + 1 /* pad */ ;
4260 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4261 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4262 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4263 pSMB->Pad = 0;
4264 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004265 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004266 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004267
4268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4269 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4270 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004271 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004272 } else { /* decode response */
4273 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4274
Jeff Layton820a8032011-05-04 08:05:26 -04004275 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004276 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 -05004277 rc = -EIO; /* bad smb */
4278 } else {
4279 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4280 memcpy((char *) pFindData,
4281 (char *) &pSMBr->hdr.Protocol +
4282 data_offset,
4283 sizeof(FILE_UNIX_BASIC_INFO));
4284 }
4285 }
4286
4287 cifs_buf_release(pSMB);
4288 if (rc == -EAGAIN)
4289 goto UnixQFileInfoRetry;
4290
4291 return rc;
4292}
4293
4294int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004295CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004297 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004298 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299{
4300/* SMB_QUERY_FILE_UNIX_BASIC */
4301 TRANSACTION2_QPI_REQ *pSMB = NULL;
4302 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4303 int rc = 0;
4304 int bytes_returned = 0;
4305 int name_len;
4306 __u16 params, byte_count;
4307
Joe Perchesf96637b2013-05-04 22:12:25 -05004308 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309UnixQPathInfoRetry:
4310 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4311 (void **) &pSMBr);
4312 if (rc)
4313 return rc;
4314
4315 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4316 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004317 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4318 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 name_len++; /* trailing null */
4320 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004321 } else {
4322 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 }
4324
Steve French50c2f752007-07-13 00:33:32 +00004325 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 pSMB->TotalDataCount = 0;
4327 pSMB->MaxParameterCount = cpu_to_le16(2);
4328 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004329 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 pSMB->MaxSetupCount = 0;
4331 pSMB->Reserved = 0;
4332 pSMB->Flags = 0;
4333 pSMB->Timeout = 0;
4334 pSMB->Reserved2 = 0;
4335 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004336 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 pSMB->DataCount = 0;
4338 pSMB->DataOffset = 0;
4339 pSMB->SetupCount = 1;
4340 pSMB->Reserved3 = 0;
4341 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4342 byte_count = params + 1 /* pad */ ;
4343 pSMB->TotalParameterCount = cpu_to_le16(params);
4344 pSMB->ParameterCount = pSMB->TotalParameterCount;
4345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4346 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004347 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 pSMB->ByteCount = cpu_to_le16(byte_count);
4349
4350 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4351 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4352 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004353 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 } else { /* decode response */
4355 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4356
Jeff Layton820a8032011-05-04 08:05:26 -04004357 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004358 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 -07004359 rc = -EIO; /* bad smb */
4360 } else {
4361 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4362 memcpy((char *) pFindData,
4363 (char *) &pSMBr->hdr.Protocol +
4364 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004365 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 }
4367 }
4368 cifs_buf_release(pSMB);
4369 if (rc == -EAGAIN)
4370 goto UnixQPathInfoRetry;
4371
4372 return rc;
4373}
4374
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375/* xid, tcon, searchName and codepage are input parms, rest are returned */
4376int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004377CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004378 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004379 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004380 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381{
4382/* level 257 SMB_ */
4383 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4384 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004385 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 int rc = 0;
4387 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004388 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004390 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
Joe Perchesf96637b2013-05-04 22:12:25 -05004392 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
4394findFirstRetry:
4395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4396 (void **) &pSMBr);
4397 if (rc)
4398 return rc;
4399
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004400 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004401 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004402
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4404 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004405 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4406 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004407 /* We can not add the asterik earlier in case
4408 it got remapped to 0xF03A as if it were part of the
4409 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004411 if (msearch) {
4412 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4413 pSMB->FileName[name_len+1] = 0;
4414 pSMB->FileName[name_len+2] = '*';
4415 pSMB->FileName[name_len+3] = 0;
4416 name_len += 4; /* now the trailing null */
4417 /* null terminate just in case */
4418 pSMB->FileName[name_len] = 0;
4419 pSMB->FileName[name_len+1] = 0;
4420 name_len += 2;
4421 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004422 } else {
4423 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004424 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004425 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4426 name_len = PATH_MAX-2;
4427 /* overwrite nul byte */
4428 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4429 pSMB->FileName[name_len] = '*';
4430 pSMB->FileName[name_len+1] = 0;
4431 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 }
4434
4435 params = 12 + name_len /* includes null */ ;
4436 pSMB->TotalDataCount = 0; /* no EAs */
4437 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004438 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 pSMB->MaxSetupCount = 0;
4440 pSMB->Reserved = 0;
4441 pSMB->Flags = 0;
4442 pSMB->Timeout = 0;
4443 pSMB->Reserved2 = 0;
4444 byte_count = params + 1 /* pad */ ;
4445 pSMB->TotalParameterCount = cpu_to_le16(params);
4446 pSMB->ParameterCount = pSMB->TotalParameterCount;
4447 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004448 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4449 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 pSMB->DataCount = 0;
4451 pSMB->DataOffset = 0;
4452 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4453 pSMB->Reserved3 = 0;
4454 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4455 pSMB->SearchAttributes =
4456 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4457 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004458 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004459 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4461
4462 /* BB what should we set StorageType to? Does it matter? BB */
4463 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004464 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 pSMB->ByteCount = cpu_to_le16(byte_count);
4466
4467 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4468 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004469 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470
Steve French88274812006-03-09 22:21:45 +00004471 if (rc) {/* BB add logic to retry regular search if Unix search
4472 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004474 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004475
Steve French88274812006-03-09 22:21:45 +00004476 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477
4478 /* BB eventually could optimize out free and realloc of buf */
4479 /* for this case */
4480 if (rc == -EAGAIN)
4481 goto findFirstRetry;
4482 } else { /* decode response */
4483 /* BB remember to free buffer if error BB */
4484 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004485 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004486 unsigned int lnoff;
4487
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004489 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 else
Steve French4b18f2a2008-04-29 00:06:05 +00004491 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492
4493 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
zhengbin01d1bd72019-12-25 11:30:21 +08004494 psrch_inf->smallBuf = false;
Steve French50c2f752007-07-13 00:33:32 +00004495 psrch_inf->srch_entries_start =
4496 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4499 le16_to_cpu(pSMBr->t2.ParameterOffset));
4500
Steve French790fe572007-07-07 19:25:05 +00004501 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004502 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 else
Steve French4b18f2a2008-04-29 00:06:05 +00004504 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505
Steve French50c2f752007-07-13 00:33:32 +00004506 psrch_inf->entries_in_buffer =
4507 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004508 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004510 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004511 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004512 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004513 psrch_inf->last_entry = NULL;
4514 return rc;
4515 }
4516
Steve French0752f152008-10-07 20:03:33 +00004517 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004518 lnoff;
4519
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004520 if (pnetfid)
4521 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 } else {
4523 cifs_buf_release(pSMB);
4524 }
4525 }
4526
4527 return rc;
4528}
4529
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004530int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4531 __u16 searchHandle, __u16 search_flags,
4532 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533{
4534 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4535 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004536 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 char *response_data;
4538 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004539 int bytes_returned;
4540 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 __u16 params, byte_count;
4542
Joe Perchesf96637b2013-05-04 22:12:25 -05004543 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
Steve French4b18f2a2008-04-29 00:06:05 +00004545 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 return -ENOENT;
4547
4548 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4549 (void **) &pSMBr);
4550 if (rc)
4551 return rc;
4552
Steve French50c2f752007-07-13 00:33:32 +00004553 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 byte_count = 0;
4555 pSMB->TotalDataCount = 0; /* no EAs */
4556 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004557 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 pSMB->MaxSetupCount = 0;
4559 pSMB->Reserved = 0;
4560 pSMB->Flags = 0;
4561 pSMB->Timeout = 0;
4562 pSMB->Reserved2 = 0;
4563 pSMB->ParameterOffset = cpu_to_le16(
4564 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4565 pSMB->DataCount = 0;
4566 pSMB->DataOffset = 0;
4567 pSMB->SetupCount = 1;
4568 pSMB->Reserved3 = 0;
4569 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4570 pSMB->SearchHandle = searchHandle; /* always kept as le */
4571 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004572 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4574 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004575 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576
4577 name_len = psrch_inf->resume_name_len;
4578 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004579 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4581 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004582 /* 14 byte parm len above enough for 2 byte null terminator */
4583 pSMB->ResumeFileName[name_len] = 0;
4584 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 } else {
4586 rc = -EINVAL;
4587 goto FNext2_err_exit;
4588 }
4589 byte_count = params + 1 /* pad */ ;
4590 pSMB->TotalParameterCount = cpu_to_le16(params);
4591 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004592 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004594
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004597 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 if (rc) {
4599 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004600 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004601 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004602 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004604 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 } else { /* decode response */
4606 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004607
Steve French790fe572007-07-07 19:25:05 +00004608 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004609 unsigned int lnoff;
4610
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 /* BB fixme add lock for file (srch_info) struct here */
4612 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004613 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 else
Steve French4b18f2a2008-04-29 00:06:05 +00004615 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 response_data = (char *) &pSMBr->hdr.Protocol +
4617 le16_to_cpu(pSMBr->t2.ParameterOffset);
4618 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4619 response_data = (char *)&pSMBr->hdr.Protocol +
4620 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004621 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004622 cifs_small_buf_release(
4623 psrch_inf->ntwrk_buf_start);
4624 else
4625 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 psrch_inf->srch_entries_start = response_data;
4627 psrch_inf->ntwrk_buf_start = (char *)pSMB;
zhengbin01d1bd72019-12-25 11:30:21 +08004628 psrch_inf->smallBuf = false;
Steve French790fe572007-07-07 19:25:05 +00004629 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004630 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 else
Steve French4b18f2a2008-04-29 00:06:05 +00004632 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004633 psrch_inf->entries_in_buffer =
4634 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 psrch_inf->index_of_last_entry +=
4636 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004637 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004638 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004639 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004640 psrch_inf->last_entry = NULL;
4641 return rc;
4642 } else
4643 psrch_inf->last_entry =
4644 psrch_inf->srch_entries_start + lnoff;
4645
Joe Perchesf96637b2013-05-04 22:12:25 -05004646/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4647 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648
4649 /* BB fixme add unlock here */
4650 }
4651
4652 }
4653
4654 /* BB On error, should we leave previous search buf (and count and
4655 last entry fields) intact or free the previous one? */
4656
4657 /* Note: On -EAGAIN error only caller can retry on handle based calls
4658 since file handle passed in no longer valid */
4659FNext2_err_exit:
4660 if (rc != 0)
4661 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 return rc;
4663}
4664
4665int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004666CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004667 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668{
4669 int rc = 0;
4670 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671
Joe Perchesf96637b2013-05-04 22:12:25 -05004672 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4674
4675 /* no sense returning error if session restarted
4676 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004677 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 return 0;
4679 if (rc)
4680 return rc;
4681
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 pSMB->FileID = searchHandle;
4683 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004684 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004685 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004686 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004687 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004688
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004689 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
4691 /* Since session is dead, search handle closed on server already */
4692 if (rc == -EAGAIN)
4693 rc = 0;
4694
4695 return rc;
4696}
4697
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004699CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004700 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004701 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702{
4703 int rc = 0;
4704 TRANSACTION2_QPI_REQ *pSMB = NULL;
4705 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4706 int name_len, bytes_returned;
4707 __u16 params, byte_count;
4708
Joe Perchesf96637b2013-05-04 22:12:25 -05004709 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004710 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004711 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712
4713GetInodeNumberRetry:
4714 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004715 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 if (rc)
4717 return rc;
4718
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4720 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004721 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004722 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004723 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 name_len++; /* trailing null */
4725 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004726 } else {
4727 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 }
4729
4730 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4731 pSMB->TotalDataCount = 0;
4732 pSMB->MaxParameterCount = cpu_to_le16(2);
4733 /* BB find exact max data count below from sess structure BB */
4734 pSMB->MaxDataCount = cpu_to_le16(4000);
4735 pSMB->MaxSetupCount = 0;
4736 pSMB->Reserved = 0;
4737 pSMB->Flags = 0;
4738 pSMB->Timeout = 0;
4739 pSMB->Reserved2 = 0;
4740 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004741 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 pSMB->DataCount = 0;
4743 pSMB->DataOffset = 0;
4744 pSMB->SetupCount = 1;
4745 pSMB->Reserved3 = 0;
4746 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4747 byte_count = params + 1 /* pad */ ;
4748 pSMB->TotalParameterCount = cpu_to_le16(params);
4749 pSMB->ParameterCount = pSMB->TotalParameterCount;
4750 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4751 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004752 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 pSMB->ByteCount = cpu_to_le16(byte_count);
4754
4755 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4756 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4757 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004758 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 } else {
4760 /* decode response */
4761 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004763 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 /* If rc should we check for EOPNOSUPP and
4765 disable the srvino flag? or in caller? */
4766 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004767 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4769 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004770 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004772 if (count < 8) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004773 cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 rc = -EIO;
4775 goto GetInodeNumOut;
4776 }
4777 pfinfo = (struct file_internal_info *)
4778 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004779 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 }
4781 }
4782GetInodeNumOut:
4783 cifs_buf_release(pSMB);
4784 if (rc == -EAGAIN)
4785 goto GetInodeNumberRetry;
4786 return rc;
4787}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788
4789int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004790CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004791 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004792 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004793 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794{
4795/* TRANS2_GET_DFS_REFERRAL */
4796 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4797 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 int rc = 0;
4799 int bytes_returned;
4800 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004802 *num_of_nodes = 0;
4803 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804
Joe Perchesf96637b2013-05-04 22:12:25 -05004805 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004806 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004808
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004810 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 (void **) &pSMBr);
4812 if (rc)
4813 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004814
4815 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004816 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004817 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004818 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004820 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004822 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824
4825 if (ses->capabilities & CAP_UNICODE) {
4826 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4827 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004828 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004829 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004830 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 name_len++; /* trailing null */
4832 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004833 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004834 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 }
4836
Dan Carpenter65c3b202015-04-30 17:30:24 +03004837 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004838 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004839
Steve French50c2f752007-07-13 00:33:32 +00004840 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004841
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 params = 2 /* level */ + name_len /*includes null */ ;
4843 pSMB->TotalDataCount = 0;
4844 pSMB->DataCount = 0;
4845 pSMB->DataOffset = 0;
4846 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004847 /* BB find exact max SMB PDU from sess structure BB */
4848 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 pSMB->MaxSetupCount = 0;
4850 pSMB->Reserved = 0;
4851 pSMB->Flags = 0;
4852 pSMB->Timeout = 0;
4853 pSMB->Reserved2 = 0;
4854 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004855 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 pSMB->SetupCount = 1;
4857 pSMB->Reserved3 = 0;
4858 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4859 byte_count = params + 3 /* pad */ ;
4860 pSMB->ParameterCount = cpu_to_le16(params);
4861 pSMB->TotalParameterCount = pSMB->ParameterCount;
4862 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004863 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 pSMB->ByteCount = cpu_to_le16(byte_count);
4865
4866 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4868 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004869 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004870 goto GetDFSRefExit;
4871 }
4872 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004874 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004875 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004876 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004877 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004879
Joe Perchesf96637b2013-05-04 22:12:25 -05004880 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4881 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004882
4883 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004884 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4885 le16_to_cpu(pSMBr->t2.DataCount),
4886 num_of_nodes, target_nodes, nls_codepage,
4887 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004888 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004889
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004891 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
4893 if (rc == -EAGAIN)
4894 goto getDFSRetry;
4895
4896 return rc;
4897}
4898
Steve French20962432005-09-21 22:05:57 -07004899/* Query File System Info such as free space to old servers such as Win 9x */
4900int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004901SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4902 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004903{
4904/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4905 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4906 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4907 FILE_SYSTEM_ALLOC_INFO *response_data;
4908 int rc = 0;
4909 int bytes_returned = 0;
4910 __u16 params, byte_count;
4911
Joe Perchesf96637b2013-05-04 22:12:25 -05004912 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004913oldQFSInfoRetry:
4914 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4915 (void **) &pSMBr);
4916 if (rc)
4917 return rc;
Steve French20962432005-09-21 22:05:57 -07004918
4919 params = 2; /* level */
4920 pSMB->TotalDataCount = 0;
4921 pSMB->MaxParameterCount = cpu_to_le16(2);
4922 pSMB->MaxDataCount = cpu_to_le16(1000);
4923 pSMB->MaxSetupCount = 0;
4924 pSMB->Reserved = 0;
4925 pSMB->Flags = 0;
4926 pSMB->Timeout = 0;
4927 pSMB->Reserved2 = 0;
4928 byte_count = params + 1 /* pad */ ;
4929 pSMB->TotalParameterCount = cpu_to_le16(params);
4930 pSMB->ParameterCount = pSMB->TotalParameterCount;
4931 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4932 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4933 pSMB->DataCount = 0;
4934 pSMB->DataOffset = 0;
4935 pSMB->SetupCount = 1;
4936 pSMB->Reserved3 = 0;
4937 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4938 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004939 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004940 pSMB->ByteCount = cpu_to_le16(byte_count);
4941
4942 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4943 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4944 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004945 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004946 } else { /* decode response */
4947 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4948
Jeff Layton820a8032011-05-04 08:05:26 -04004949 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004950 rc = -EIO; /* bad smb */
4951 else {
4952 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004953 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004954 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004955
Steve French50c2f752007-07-13 00:33:32 +00004956 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004957 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4958 FSData->f_bsize =
4959 le16_to_cpu(response_data->BytesPerSector) *
4960 le32_to_cpu(response_data->
4961 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05004962 /*
4963 * much prefer larger but if server doesn't report
4964 * a valid size than 4K is a reasonable minimum
4965 */
4966 if (FSData->f_bsize < 512)
4967 FSData->f_bsize = 4096;
4968
Steve French20962432005-09-21 22:05:57 -07004969 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004970 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004971 FSData->f_bfree = FSData->f_bavail =
4972 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004973 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4974 (unsigned long long)FSData->f_blocks,
4975 (unsigned long long)FSData->f_bfree,
4976 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004977 }
4978 }
4979 cifs_buf_release(pSMB);
4980
4981 if (rc == -EAGAIN)
4982 goto oldQFSInfoRetry;
4983
4984 return rc;
4985}
4986
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004988CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4989 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990{
4991/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4992 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4993 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4994 FILE_SYSTEM_INFO *response_data;
4995 int rc = 0;
4996 int bytes_returned = 0;
4997 __u16 params, byte_count;
4998
Joe Perchesf96637b2013-05-04 22:12:25 -05004999 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000QFSInfoRetry:
5001 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5002 (void **) &pSMBr);
5003 if (rc)
5004 return rc;
5005
5006 params = 2; /* level */
5007 pSMB->TotalDataCount = 0;
5008 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005009 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 pSMB->MaxSetupCount = 0;
5011 pSMB->Reserved = 0;
5012 pSMB->Flags = 0;
5013 pSMB->Timeout = 0;
5014 pSMB->Reserved2 = 0;
5015 byte_count = params + 1 /* pad */ ;
5016 pSMB->TotalParameterCount = cpu_to_le16(params);
5017 pSMB->ParameterCount = pSMB->TotalParameterCount;
5018 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005019 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 pSMB->DataCount = 0;
5021 pSMB->DataOffset = 0;
5022 pSMB->SetupCount = 1;
5023 pSMB->Reserved3 = 0;
5024 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5025 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005026 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 pSMB->ByteCount = cpu_to_le16(byte_count);
5028
5029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5031 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005032 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
Jeff Layton820a8032011-05-04 08:05:26 -04005036 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 rc = -EIO; /* bad smb */
5038 else {
5039 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040
5041 response_data =
5042 (FILE_SYSTEM_INFO
5043 *) (((char *) &pSMBr->hdr.Protocol) +
5044 data_offset);
5045 FSData->f_bsize =
5046 le32_to_cpu(response_data->BytesPerSector) *
5047 le32_to_cpu(response_data->
5048 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005049 /*
5050 * much prefer larger but if server doesn't report
5051 * a valid size than 4K is a reasonable minimum
5052 */
5053 if (FSData->f_bsize < 512)
5054 FSData->f_bsize = 4096;
5055
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 FSData->f_blocks =
5057 le64_to_cpu(response_data->TotalAllocationUnits);
5058 FSData->f_bfree = FSData->f_bavail =
5059 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005060 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5061 (unsigned long long)FSData->f_blocks,
5062 (unsigned long long)FSData->f_bfree,
5063 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 }
5065 }
5066 cifs_buf_release(pSMB);
5067
5068 if (rc == -EAGAIN)
5069 goto QFSInfoRetry;
5070
5071 return rc;
5072}
5073
5074int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005075CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076{
5077/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5078 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5079 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5080 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5081 int rc = 0;
5082 int bytes_returned = 0;
5083 __u16 params, byte_count;
5084
Joe Perchesf96637b2013-05-04 22:12:25 -05005085 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086QFSAttributeRetry:
5087 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5088 (void **) &pSMBr);
5089 if (rc)
5090 return rc;
5091
5092 params = 2; /* level */
5093 pSMB->TotalDataCount = 0;
5094 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005095 /* BB find exact max SMB PDU from sess structure BB */
5096 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 pSMB->MaxSetupCount = 0;
5098 pSMB->Reserved = 0;
5099 pSMB->Flags = 0;
5100 pSMB->Timeout = 0;
5101 pSMB->Reserved2 = 0;
5102 byte_count = params + 1 /* pad */ ;
5103 pSMB->TotalParameterCount = cpu_to_le16(params);
5104 pSMB->ParameterCount = pSMB->TotalParameterCount;
5105 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005106 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 pSMB->DataCount = 0;
5108 pSMB->DataOffset = 0;
5109 pSMB->SetupCount = 1;
5110 pSMB->Reserved3 = 0;
5111 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5112 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005113 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 pSMB->ByteCount = cpu_to_le16(byte_count);
5115
5116 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5117 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5118 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005119 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 } else { /* decode response */
5121 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5122
Jeff Layton820a8032011-05-04 08:05:26 -04005123 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005124 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 rc = -EIO; /* bad smb */
5126 } else {
5127 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5128 response_data =
5129 (FILE_SYSTEM_ATTRIBUTE_INFO
5130 *) (((char *) &pSMBr->hdr.Protocol) +
5131 data_offset);
5132 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005133 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 }
5135 }
5136 cifs_buf_release(pSMB);
5137
5138 if (rc == -EAGAIN)
5139 goto QFSAttributeRetry;
5140
5141 return rc;
5142}
5143
5144int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005145CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146{
5147/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5148 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5149 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5150 FILE_SYSTEM_DEVICE_INFO *response_data;
5151 int rc = 0;
5152 int bytes_returned = 0;
5153 __u16 params, byte_count;
5154
Joe Perchesf96637b2013-05-04 22:12:25 -05005155 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156QFSDeviceRetry:
5157 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5158 (void **) &pSMBr);
5159 if (rc)
5160 return rc;
5161
5162 params = 2; /* level */
5163 pSMB->TotalDataCount = 0;
5164 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005165 /* BB find exact max SMB PDU from sess structure BB */
5166 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 pSMB->MaxSetupCount = 0;
5168 pSMB->Reserved = 0;
5169 pSMB->Flags = 0;
5170 pSMB->Timeout = 0;
5171 pSMB->Reserved2 = 0;
5172 byte_count = params + 1 /* pad */ ;
5173 pSMB->TotalParameterCount = cpu_to_le16(params);
5174 pSMB->ParameterCount = pSMB->TotalParameterCount;
5175 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005176 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177
5178 pSMB->DataCount = 0;
5179 pSMB->DataOffset = 0;
5180 pSMB->SetupCount = 1;
5181 pSMB->Reserved3 = 0;
5182 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5183 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005184 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 pSMB->ByteCount = cpu_to_le16(byte_count);
5186
5187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5189 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005190 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 } else { /* decode response */
5192 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5193
Jeff Layton820a8032011-05-04 08:05:26 -04005194 if (rc || get_bcc(&pSMBr->hdr) <
5195 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 rc = -EIO; /* bad smb */
5197 else {
5198 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5199 response_data =
Steve French737b7582005-04-28 22:41:06 -07005200 (FILE_SYSTEM_DEVICE_INFO *)
5201 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 data_offset);
5203 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005204 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 }
5206 }
5207 cifs_buf_release(pSMB);
5208
5209 if (rc == -EAGAIN)
5210 goto QFSDeviceRetry;
5211
5212 return rc;
5213}
5214
5215int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005216CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217{
5218/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5219 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5220 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5221 FILE_SYSTEM_UNIX_INFO *response_data;
5222 int rc = 0;
5223 int bytes_returned = 0;
5224 __u16 params, byte_count;
5225
Joe Perchesf96637b2013-05-04 22:12:25 -05005226 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005228 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5229 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 if (rc)
5231 return rc;
5232
5233 params = 2; /* level */
5234 pSMB->TotalDataCount = 0;
5235 pSMB->DataCount = 0;
5236 pSMB->DataOffset = 0;
5237 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005238 /* BB find exact max SMB PDU from sess structure BB */
5239 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 pSMB->MaxSetupCount = 0;
5241 pSMB->Reserved = 0;
5242 pSMB->Flags = 0;
5243 pSMB->Timeout = 0;
5244 pSMB->Reserved2 = 0;
5245 byte_count = params + 1 /* pad */ ;
5246 pSMB->ParameterCount = cpu_to_le16(params);
5247 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005248 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5249 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 pSMB->SetupCount = 1;
5251 pSMB->Reserved3 = 0;
5252 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5253 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005254 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 pSMB->ByteCount = cpu_to_le16(byte_count);
5256
5257 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5258 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5259 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005260 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 } else { /* decode response */
5262 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5263
Jeff Layton820a8032011-05-04 08:05:26 -04005264 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 rc = -EIO; /* bad smb */
5266 } else {
5267 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5268 response_data =
5269 (FILE_SYSTEM_UNIX_INFO
5270 *) (((char *) &pSMBr->hdr.Protocol) +
5271 data_offset);
5272 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005273 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 }
5275 }
5276 cifs_buf_release(pSMB);
5277
5278 if (rc == -EAGAIN)
5279 goto QFSUnixRetry;
5280
5281
5282 return rc;
5283}
5284
Jeremy Allisonac670552005-06-22 17:26:35 -07005285int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005286CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005287{
5288/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5289 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5290 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5291 int rc = 0;
5292 int bytes_returned = 0;
5293 __u16 params, param_offset, offset, byte_count;
5294
Joe Perchesf96637b2013-05-04 22:12:25 -05005295 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005296SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005297 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005298 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5299 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005300 if (rc)
5301 return rc;
5302
5303 params = 4; /* 2 bytes zero followed by info level. */
5304 pSMB->MaxSetupCount = 0;
5305 pSMB->Reserved = 0;
5306 pSMB->Flags = 0;
5307 pSMB->Timeout = 0;
5308 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005309 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5310 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005311 offset = param_offset + params;
5312
5313 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005314 /* BB find exact max SMB PDU from sess structure BB */
5315 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005316 pSMB->SetupCount = 1;
5317 pSMB->Reserved3 = 0;
5318 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5319 byte_count = 1 /* pad */ + params + 12;
5320
5321 pSMB->DataCount = cpu_to_le16(12);
5322 pSMB->ParameterCount = cpu_to_le16(params);
5323 pSMB->TotalDataCount = pSMB->DataCount;
5324 pSMB->TotalParameterCount = pSMB->ParameterCount;
5325 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5326 pSMB->DataOffset = cpu_to_le16(offset);
5327
5328 /* Params. */
5329 pSMB->FileNum = 0;
5330 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5331
5332 /* Data. */
5333 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5334 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5335 pSMB->ClientUnixCap = cpu_to_le64(cap);
5336
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005337 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005338 pSMB->ByteCount = cpu_to_le16(byte_count);
5339
5340 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5341 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5342 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005343 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005344 } else { /* decode response */
5345 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005346 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005347 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005348 }
5349 cifs_buf_release(pSMB);
5350
5351 if (rc == -EAGAIN)
5352 goto SETFSUnixRetry;
5353
5354 return rc;
5355}
5356
5357
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358
5359int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005360CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005361 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362{
5363/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5364 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5365 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5366 FILE_SYSTEM_POSIX_INFO *response_data;
5367 int rc = 0;
5368 int bytes_returned = 0;
5369 __u16 params, byte_count;
5370
Joe Perchesf96637b2013-05-04 22:12:25 -05005371 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372QFSPosixRetry:
5373 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5374 (void **) &pSMBr);
5375 if (rc)
5376 return rc;
5377
5378 params = 2; /* level */
5379 pSMB->TotalDataCount = 0;
5380 pSMB->DataCount = 0;
5381 pSMB->DataOffset = 0;
5382 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005383 /* BB find exact max SMB PDU from sess structure BB */
5384 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 pSMB->MaxSetupCount = 0;
5386 pSMB->Reserved = 0;
5387 pSMB->Flags = 0;
5388 pSMB->Timeout = 0;
5389 pSMB->Reserved2 = 0;
5390 byte_count = params + 1 /* pad */ ;
5391 pSMB->ParameterCount = cpu_to_le16(params);
5392 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005393 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5394 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 pSMB->SetupCount = 1;
5396 pSMB->Reserved3 = 0;
5397 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5398 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005399 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 pSMB->ByteCount = cpu_to_le16(byte_count);
5401
5402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5404 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005405 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 } else { /* decode response */
5407 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5408
Jeff Layton820a8032011-05-04 08:05:26 -04005409 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 rc = -EIO; /* bad smb */
5411 } else {
5412 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5413 response_data =
5414 (FILE_SYSTEM_POSIX_INFO
5415 *) (((char *) &pSMBr->hdr.Protocol) +
5416 data_offset);
5417 FSData->f_bsize =
5418 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005419 /*
5420 * much prefer larger but if server doesn't report
5421 * a valid size than 4K is a reasonable minimum
5422 */
5423 if (FSData->f_bsize < 512)
5424 FSData->f_bsize = 4096;
5425
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 FSData->f_blocks =
5427 le64_to_cpu(response_data->TotalBlocks);
5428 FSData->f_bfree =
5429 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005430 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 FSData->f_bavail = FSData->f_bfree;
5432 } else {
5433 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005434 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 }
Steve French790fe572007-07-07 19:25:05 +00005436 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005438 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005439 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005441 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 }
5443 }
5444 cifs_buf_release(pSMB);
5445
5446 if (rc == -EAGAIN)
5447 goto QFSPosixRetry;
5448
5449 return rc;
5450}
5451
5452
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005453/*
5454 * We can not use write of zero bytes trick to set file size due to need for
5455 * large file support. Also note that this SetPathInfo is preferred to
5456 * SetFileInfo based method in next routine which is only needed to work around
5457 * a sharing violation bugin Samba which this routine can run into.
5458 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005460CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005461 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5462 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463{
5464 struct smb_com_transaction2_spi_req *pSMB = NULL;
5465 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5466 struct file_end_of_file_info *parm_data;
5467 int name_len;
5468 int rc = 0;
5469 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005470 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005471
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 __u16 params, byte_count, data_count, param_offset, offset;
5473
Joe Perchesf96637b2013-05-04 22:12:25 -05005474 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475SetEOFRetry:
5476 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5477 (void **) &pSMBr);
5478 if (rc)
5479 return rc;
5480
5481 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5482 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005483 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5484 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 name_len++; /* trailing null */
5486 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005487 } else {
5488 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 }
5490 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005491 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005493 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 pSMB->MaxSetupCount = 0;
5495 pSMB->Reserved = 0;
5496 pSMB->Flags = 0;
5497 pSMB->Timeout = 0;
5498 pSMB->Reserved2 = 0;
5499 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005500 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005502 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005503 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5504 pSMB->InformationLevel =
5505 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5506 else
5507 pSMB->InformationLevel =
5508 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5509 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5511 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005512 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 else
5514 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005515 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 }
5517
5518 parm_data =
5519 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5520 offset);
5521 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5522 pSMB->DataOffset = cpu_to_le16(offset);
5523 pSMB->SetupCount = 1;
5524 pSMB->Reserved3 = 0;
5525 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5526 byte_count = 3 /* pad */ + params + data_count;
5527 pSMB->DataCount = cpu_to_le16(data_count);
5528 pSMB->TotalDataCount = pSMB->DataCount;
5529 pSMB->ParameterCount = cpu_to_le16(params);
5530 pSMB->TotalParameterCount = pSMB->ParameterCount;
5531 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005532 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 parm_data->FileSize = cpu_to_le64(size);
5534 pSMB->ByteCount = cpu_to_le16(byte_count);
5535 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5536 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005537 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005538 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539
5540 cifs_buf_release(pSMB);
5541
5542 if (rc == -EAGAIN)
5543 goto SetEOFRetry;
5544
5545 return rc;
5546}
5547
5548int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005549CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5550 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551{
5552 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 struct file_end_of_file_info *parm_data;
5554 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 __u16 params, param_offset, offset, byte_count, count;
5556
Joe Perchesf96637b2013-05-04 22:12:25 -05005557 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5558 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005559 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5560
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 if (rc)
5562 return rc;
5563
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005564 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5565 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005566
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 params = 6;
5568 pSMB->MaxSetupCount = 0;
5569 pSMB->Reserved = 0;
5570 pSMB->Flags = 0;
5571 pSMB->Timeout = 0;
5572 pSMB->Reserved2 = 0;
5573 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5574 offset = param_offset + params;
5575
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 count = sizeof(struct file_end_of_file_info);
5577 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005578 /* BB find exact max SMB PDU from sess structure BB */
5579 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 pSMB->SetupCount = 1;
5581 pSMB->Reserved3 = 0;
5582 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5583 byte_count = 3 /* pad */ + params + count;
5584 pSMB->DataCount = cpu_to_le16(count);
5585 pSMB->ParameterCount = cpu_to_le16(params);
5586 pSMB->TotalDataCount = pSMB->DataCount;
5587 pSMB->TotalParameterCount = pSMB->ParameterCount;
5588 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve Frenche3973ea2021-07-06 21:27:26 -05005589 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 parm_data =
Steve Frenche3973ea2021-07-06 21:27:26 -05005591 (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 pSMB->DataOffset = cpu_to_le16(offset);
5593 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005594 pSMB->Fid = cfile->fid.netfid;
5595 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5597 pSMB->InformationLevel =
5598 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5599 else
5600 pSMB->InformationLevel =
5601 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005602 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5604 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005605 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 else
5607 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005608 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 }
5610 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005611 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005613 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005614 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005616 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5617 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 }
5619
Steve French50c2f752007-07-13 00:33:32 +00005620 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 since file handle passed in no longer valid */
5622
5623 return rc;
5624}
5625
Steve French50c2f752007-07-13 00:33:32 +00005626/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 an open handle, rather than by pathname - this is awkward due to
5628 potential access conflicts on the open, but it is unavoidable for these
5629 old servers since the only other choice is to go from 100 nanosecond DCE
5630 time and resort to the original setpathinfo level which takes the ancient
5631 DOS time format with 2 second granularity */
5632int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005633CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005634 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635{
5636 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 char *data_offset;
5638 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 __u16 params, param_offset, offset, byte_count, count;
5640
Joe Perchesf96637b2013-05-04 22:12:25 -05005641 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005642 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5643
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 if (rc)
5645 return rc;
5646
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005647 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5648 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005649
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 params = 6;
5651 pSMB->MaxSetupCount = 0;
5652 pSMB->Reserved = 0;
5653 pSMB->Flags = 0;
5654 pSMB->Timeout = 0;
5655 pSMB->Reserved2 = 0;
5656 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5657 offset = param_offset + params;
5658
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005659 data_offset = (char *)pSMB +
5660 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661
Steve French26f57362007-08-30 22:09:15 +00005662 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005664 /* BB find max SMB PDU from sess */
5665 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 pSMB->SetupCount = 1;
5667 pSMB->Reserved3 = 0;
5668 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5669 byte_count = 3 /* pad */ + params + count;
5670 pSMB->DataCount = cpu_to_le16(count);
5671 pSMB->ParameterCount = cpu_to_le16(params);
5672 pSMB->TotalDataCount = pSMB->DataCount;
5673 pSMB->TotalParameterCount = pSMB->ParameterCount;
5674 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5675 pSMB->DataOffset = cpu_to_le16(offset);
5676 pSMB->Fid = fid;
5677 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5678 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5679 else
5680 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5681 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005682 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005684 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005685 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005686 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005687 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005688 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5689 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
Steve French50c2f752007-07-13 00:33:32 +00005691 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 since file handle passed in no longer valid */
5693
5694 return rc;
5695}
5696
Jeff Layton6d22f092008-09-23 11:48:35 -04005697int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005698CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005699 bool delete_file, __u16 fid, __u32 pid_of_opener)
5700{
5701 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5702 char *data_offset;
5703 int rc = 0;
5704 __u16 params, param_offset, offset, byte_count, count;
5705
Joe Perchesf96637b2013-05-04 22:12:25 -05005706 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005707 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5708
5709 if (rc)
5710 return rc;
5711
5712 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5713 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5714
5715 params = 6;
5716 pSMB->MaxSetupCount = 0;
5717 pSMB->Reserved = 0;
5718 pSMB->Flags = 0;
5719 pSMB->Timeout = 0;
5720 pSMB->Reserved2 = 0;
5721 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5722 offset = param_offset + params;
5723
Steve French2a780e82021-07-06 21:42:08 -05005724 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
5725 data_offset = (char *)(pSMB) + offset + 4;
Jeff Layton6d22f092008-09-23 11:48:35 -04005726
5727 count = 1;
5728 pSMB->MaxParameterCount = cpu_to_le16(2);
5729 /* BB find max SMB PDU from sess */
5730 pSMB->MaxDataCount = cpu_to_le16(1000);
5731 pSMB->SetupCount = 1;
5732 pSMB->Reserved3 = 0;
5733 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5734 byte_count = 3 /* pad */ + params + count;
5735 pSMB->DataCount = cpu_to_le16(count);
5736 pSMB->ParameterCount = cpu_to_le16(params);
5737 pSMB->TotalDataCount = pSMB->DataCount;
5738 pSMB->TotalParameterCount = pSMB->ParameterCount;
5739 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5740 pSMB->DataOffset = cpu_to_le16(offset);
5741 pSMB->Fid = fid;
5742 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5743 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005744 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005745 pSMB->ByteCount = cpu_to_le16(byte_count);
5746 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005747 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005748 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005749 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005750 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005751
5752 return rc;
5753}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005755static int
5756CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
5757 const char *fileName, const FILE_BASIC_INFO *data,
5758 const struct nls_table *nls_codepage,
5759 struct cifs_sb_info *cifs_sb)
5760{
5761 int oplock = 0;
5762 struct cifs_open_parms oparms;
5763 struct cifs_fid fid;
5764 int rc;
5765
5766 oparms.tcon = tcon;
5767 oparms.cifs_sb = cifs_sb;
5768 oparms.desired_access = GENERIC_WRITE;
5769 oparms.create_options = cifs_create_options(cifs_sb, 0);
5770 oparms.disposition = FILE_OPEN;
5771 oparms.path = fileName;
5772 oparms.fid = &fid;
5773 oparms.reconnect = false;
5774
5775 rc = CIFS_open(xid, &oparms, &oplock, NULL);
5776 if (rc)
5777 goto out;
5778
5779 rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
5780 CIFSSMBClose(xid, tcon, fid.netfid);
5781out:
5782
5783 return rc;
5784}
5785
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005787CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005788 const char *fileName, const FILE_BASIC_INFO *data,
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005789 const struct nls_table *nls_codepage,
5790 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791{
5792 TRANSACTION2_SPI_REQ *pSMB = NULL;
5793 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5794 int name_len;
5795 int rc = 0;
5796 int bytes_returned = 0;
5797 char *data_offset;
5798 __u16 params, param_offset, offset, byte_count, count;
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005799 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800
Joe Perchesf96637b2013-05-04 22:12:25 -05005801 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
5803SetTimesRetry:
5804 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5805 (void **) &pSMBr);
5806 if (rc)
5807 return rc;
5808
5809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5810 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005811 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5812 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813 name_len++; /* trailing null */
5814 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005815 } else {
5816 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817 }
5818
5819 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005820 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005822 /* BB find max SMB PDU from sess structure BB */
5823 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824 pSMB->MaxSetupCount = 0;
5825 pSMB->Reserved = 0;
5826 pSMB->Flags = 0;
5827 pSMB->Timeout = 0;
5828 pSMB->Reserved2 = 0;
5829 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005830 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 offset = param_offset + params;
5832 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5833 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5834 pSMB->DataOffset = cpu_to_le16(offset);
5835 pSMB->SetupCount = 1;
5836 pSMB->Reserved3 = 0;
5837 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5838 byte_count = 3 /* pad */ + params + count;
5839
5840 pSMB->DataCount = cpu_to_le16(count);
5841 pSMB->ParameterCount = cpu_to_le16(params);
5842 pSMB->TotalDataCount = pSMB->DataCount;
5843 pSMB->TotalParameterCount = pSMB->ParameterCount;
5844 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5845 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5846 else
5847 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5848 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005849 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005850 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 pSMB->ByteCount = cpu_to_le16(byte_count);
5852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5853 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005854 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005855 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856
5857 cifs_buf_release(pSMB);
5858
5859 if (rc == -EAGAIN)
5860 goto SetTimesRetry;
5861
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005862 if (rc == -EOPNOTSUPP)
5863 return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
5864 nls_codepage, cifs_sb);
5865
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 return rc;
5867}
5868
Jeff Layton654cf142009-07-09 20:02:49 -04005869static void
5870cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5871 const struct cifs_unix_set_info_args *args)
5872{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005873 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005874 u64 mode = args->mode;
5875
Eric W. Biederman49418b22013-02-06 00:57:56 -08005876 if (uid_valid(args->uid))
5877 uid = from_kuid(&init_user_ns, args->uid);
5878 if (gid_valid(args->gid))
5879 gid = from_kgid(&init_user_ns, args->gid);
5880
Jeff Layton654cf142009-07-09 20:02:49 -04005881 /*
5882 * Samba server ignores set of file size to zero due to bugs in some
5883 * older clients, but we should be precise - we use SetFileSize to
5884 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005885 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005886 * zero instead of -1 here
5887 */
5888 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5889 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5890 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5891 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5892 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005893 data_offset->Uid = cpu_to_le64(uid);
5894 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005895 /* better to leave device as zero when it is */
5896 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5897 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5898 data_offset->Permissions = cpu_to_le64(mode);
5899
5900 if (S_ISREG(mode))
5901 data_offset->Type = cpu_to_le32(UNIX_FILE);
5902 else if (S_ISDIR(mode))
5903 data_offset->Type = cpu_to_le32(UNIX_DIR);
5904 else if (S_ISLNK(mode))
5905 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5906 else if (S_ISCHR(mode))
5907 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5908 else if (S_ISBLK(mode))
5909 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5910 else if (S_ISFIFO(mode))
5911 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5912 else if (S_ISSOCK(mode))
5913 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5914}
5915
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005917CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005918 const struct cifs_unix_set_info_args *args,
5919 u16 fid, u32 pid_of_opener)
5920{
5921 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005922 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005923 int rc = 0;
5924 u16 params, param_offset, offset, byte_count, count;
5925
Joe Perchesf96637b2013-05-04 22:12:25 -05005926 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005927 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5928
5929 if (rc)
5930 return rc;
5931
5932 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5933 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5934
5935 params = 6;
5936 pSMB->MaxSetupCount = 0;
5937 pSMB->Reserved = 0;
5938 pSMB->Flags = 0;
5939 pSMB->Timeout = 0;
5940 pSMB->Reserved2 = 0;
5941 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5942 offset = param_offset + params;
5943
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005944 data_offset = (char *)pSMB +
5945 offsetof(struct smb_hdr, Protocol) + offset;
5946
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005947 count = sizeof(FILE_UNIX_BASIC_INFO);
5948
5949 pSMB->MaxParameterCount = cpu_to_le16(2);
5950 /* BB find max SMB PDU from sess */
5951 pSMB->MaxDataCount = cpu_to_le16(1000);
5952 pSMB->SetupCount = 1;
5953 pSMB->Reserved3 = 0;
5954 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5955 byte_count = 3 /* pad */ + params + count;
5956 pSMB->DataCount = cpu_to_le16(count);
5957 pSMB->ParameterCount = cpu_to_le16(params);
5958 pSMB->TotalDataCount = pSMB->DataCount;
5959 pSMB->TotalParameterCount = pSMB->ParameterCount;
5960 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5961 pSMB->DataOffset = cpu_to_le16(offset);
5962 pSMB->Fid = fid;
5963 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5964 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005965 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005966 pSMB->ByteCount = cpu_to_le16(byte_count);
5967
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005968 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005969
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005970 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005971 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005972 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005973 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5974 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005975
5976 /* Note: On -EAGAIN error only caller can retry on handle based calls
5977 since file handle passed in no longer valid */
5978
5979 return rc;
5980}
5981
5982int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005983CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005984 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005985 const struct cifs_unix_set_info_args *args,
5986 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987{
5988 TRANSACTION2_SPI_REQ *pSMB = NULL;
5989 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5990 int name_len;
5991 int rc = 0;
5992 int bytes_returned = 0;
5993 FILE_UNIX_BASIC_INFO *data_offset;
5994 __u16 params, param_offset, offset, count, byte_count;
5995
Joe Perchesf96637b2013-05-04 22:12:25 -05005996 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997setPermsRetry:
5998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5999 (void **) &pSMBr);
6000 if (rc)
6001 return rc;
6002
6003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6004 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006005 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 name_len++; /* trailing null */
6008 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006009 } else {
6010 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011 }
6012
6013 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006014 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006016 /* BB find max SMB PDU from sess structure BB */
6017 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 pSMB->MaxSetupCount = 0;
6019 pSMB->Reserved = 0;
6020 pSMB->Flags = 0;
6021 pSMB->Timeout = 0;
6022 pSMB->Reserved2 = 0;
6023 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006024 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 offset = param_offset + params;
Steve Frenchb019e112021-07-01 21:01:19 -05006026 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
6027 data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 memset(data_offset, 0, count);
6029 pSMB->DataOffset = cpu_to_le16(offset);
6030 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6031 pSMB->SetupCount = 1;
6032 pSMB->Reserved3 = 0;
6033 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6034 byte_count = 3 /* pad */ + params + count;
6035 pSMB->ParameterCount = cpu_to_le16(params);
6036 pSMB->DataCount = cpu_to_le16(count);
6037 pSMB->TotalParameterCount = pSMB->ParameterCount;
6038 pSMB->TotalDataCount = pSMB->DataCount;
6039 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6040 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006041 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006042
Jeff Layton654cf142009-07-09 20:02:49 -04006043 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044
6045 pSMB->ByteCount = cpu_to_le16(byte_count);
6046 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6047 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006048 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006049 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050
Steve French0d817bc2008-05-22 02:02:03 +00006051 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 if (rc == -EAGAIN)
6053 goto setPermsRetry;
6054 return rc;
6055}
6056
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006058/*
6059 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6060 * function used by listxattr and getxattr type calls. When ea_name is set,
6061 * it looks for that attribute name and stuffs that value into the EAData
6062 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6063 * buffer. In both cases, the return value is either the length of the
6064 * resulting data or a negative error code. If EAData is a NULL pointer then
6065 * the data isn't copied to it, but the length is returned.
6066 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006068CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006069 const unsigned char *searchName, const unsigned char *ea_name,
6070 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006071 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072{
6073 /* BB assumes one setup word */
6074 TRANSACTION2_QPI_REQ *pSMB = NULL;
6075 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006076 int remap = cifs_remap(cifs_sb);
6077 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 int rc = 0;
6079 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006080 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006081 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006082 struct fea *temp_fea;
6083 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006084 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006085 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006086 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087
Joe Perchesf96637b2013-05-04 22:12:25 -05006088 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089QAllEAsRetry:
6090 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6091 (void **) &pSMBr);
6092 if (rc)
6093 return rc;
6094
6095 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006096 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006097 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6098 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006099 list_len++; /* trailing null */
6100 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006101 } else {
6102 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 }
6104
Jeff Layton6e462b92010-02-10 16:18:26 -05006105 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 pSMB->TotalDataCount = 0;
6107 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006108 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006109 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110 pSMB->MaxSetupCount = 0;
6111 pSMB->Reserved = 0;
6112 pSMB->Flags = 0;
6113 pSMB->Timeout = 0;
6114 pSMB->Reserved2 = 0;
6115 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006116 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006117 pSMB->DataCount = 0;
6118 pSMB->DataOffset = 0;
6119 pSMB->SetupCount = 1;
6120 pSMB->Reserved3 = 0;
6121 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6122 byte_count = params + 1 /* pad */ ;
6123 pSMB->TotalParameterCount = cpu_to_le16(params);
6124 pSMB->ParameterCount = pSMB->TotalParameterCount;
6125 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6126 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006127 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128 pSMB->ByteCount = cpu_to_le16(byte_count);
6129
6130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6132 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006133 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006134 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006136
6137
6138 /* BB also check enough total bytes returned */
6139 /* BB we need to improve the validity checking
6140 of these trans2 responses */
6141
6142 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006143 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006144 rc = -EIO; /* bad smb */
6145 goto QAllEAsOut;
6146 }
6147
6148 /* check that length of list is not more than bcc */
6149 /* check that each entry does not go beyond length
6150 of list */
6151 /* check that each element of each entry does not
6152 go beyond end of list */
6153 /* validate_trans2_offsets() */
6154 /* BB check if start of smb + data_offset > &bcc+ bcc */
6155
6156 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6157 ea_response_data = (struct fealist *)
6158 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6159
Jeff Layton6e462b92010-02-10 16:18:26 -05006160 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006161 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006162 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006163 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006164 /* didn't find the named attribute */
6165 if (ea_name)
6166 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006167 goto QAllEAsOut;
6168 }
6169
Jeff Layton0cd126b2010-02-10 16:18:26 -05006170 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006171 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006172 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006173 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006174 rc = -EIO;
6175 goto QAllEAsOut;
6176 }
6177
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006179 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180 temp_fea = ea_response_data->list;
6181 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006182 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006183 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006184 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006185
Jeff Layton6e462b92010-02-10 16:18:26 -05006186 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006187 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006188 /* make sure we can read name_len and value_len */
6189 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006190 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006191 rc = -EIO;
6192 goto QAllEAsOut;
6193 }
6194
6195 name_len = temp_fea->name_len;
6196 value_len = le16_to_cpu(temp_fea->value_len);
6197 list_len -= name_len + 1 + value_len;
6198 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006199 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006200 rc = -EIO;
6201 goto QAllEAsOut;
6202 }
6203
Jeff Layton31c05192010-02-10 16:18:26 -05006204 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006205 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006206 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006207 temp_ptr += name_len + 1;
6208 rc = value_len;
6209 if (buf_size == 0)
6210 goto QAllEAsOut;
6211 if ((size_t)value_len > buf_size) {
6212 rc = -ERANGE;
6213 goto QAllEAsOut;
6214 }
6215 memcpy(EAData, temp_ptr, value_len);
6216 goto QAllEAsOut;
6217 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006218 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006219 /* account for prefix user. and trailing null */
6220 rc += (5 + 1 + name_len);
6221 if (rc < (int) buf_size) {
6222 memcpy(EAData, "user.", 5);
6223 EAData += 5;
6224 memcpy(EAData, temp_ptr, name_len);
6225 EAData += name_len;
6226 /* null terminate name */
6227 *EAData = 0;
6228 ++EAData;
6229 } else if (buf_size == 0) {
6230 /* skip copy - calc size only */
6231 } else {
6232 /* stop before overrun buffer */
6233 rc = -ERANGE;
6234 break;
6235 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006236 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006237 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006238 temp_fea = (struct fea *)temp_ptr;
6239 }
6240
Jeff Layton31c05192010-02-10 16:18:26 -05006241 /* didn't find the named attribute */
6242 if (ea_name)
6243 rc = -ENODATA;
6244
Jeff Laytonf0d38682010-02-10 16:18:26 -05006245QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006246 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247 if (rc == -EAGAIN)
6248 goto QAllEAsRetry;
6249
6250 return (ssize_t)rc;
6251}
6252
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006254CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6255 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006256 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006257 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258{
6259 struct smb_com_transaction2_spi_req *pSMB = NULL;
6260 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6261 struct fealist *parm_data;
6262 int name_len;
6263 int rc = 0;
6264 int bytes_returned = 0;
6265 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006266 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267
Joe Perchesf96637b2013-05-04 22:12:25 -05006268 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269SetEARetry:
6270 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6271 (void **) &pSMBr);
6272 if (rc)
6273 return rc;
6274
6275 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6276 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006277 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6278 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 name_len++; /* trailing null */
6280 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006281 } else {
6282 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283 }
6284
6285 params = 6 + name_len;
6286
6287 /* done calculating parms using name_len of file name,
6288 now use name_len to calculate length of ea name
6289 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006290 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 name_len = 0;
6292 else
Steve French50c2f752007-07-13 00:33:32 +00006293 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006295 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006297 /* BB find max SMB PDU from sess */
6298 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006299 pSMB->MaxSetupCount = 0;
6300 pSMB->Reserved = 0;
6301 pSMB->Flags = 0;
6302 pSMB->Timeout = 0;
6303 pSMB->Reserved2 = 0;
6304 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006305 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 offset = param_offset + params;
6307 pSMB->InformationLevel =
6308 cpu_to_le16(SMB_SET_FILE_EA);
6309
Arnd Bergmannade7db92018-02-02 16:48:47 +01006310 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6312 pSMB->DataOffset = cpu_to_le16(offset);
6313 pSMB->SetupCount = 1;
6314 pSMB->Reserved3 = 0;
6315 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6316 byte_count = 3 /* pad */ + params + count;
6317 pSMB->DataCount = cpu_to_le16(count);
6318 parm_data->list_len = cpu_to_le32(count);
6319 parm_data->list[0].EA_flags = 0;
6320 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006321 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006323 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006324 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325 parm_data->list[0].name[name_len] = 0;
6326 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6327 /* caller ensures that ea_value_len is less than 64K but
6328 we need to ensure that it fits within the smb */
6329
Steve French50c2f752007-07-13 00:33:32 +00006330 /*BB add length check to see if it would fit in
6331 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006332 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6333 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006334 memcpy(parm_data->list[0].name+name_len+1,
6335 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336
6337 pSMB->TotalDataCount = pSMB->DataCount;
6338 pSMB->ParameterCount = cpu_to_le16(params);
6339 pSMB->TotalParameterCount = pSMB->ParameterCount;
6340 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006341 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 pSMB->ByteCount = cpu_to_le16(byte_count);
6343 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6344 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006345 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006346 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347
6348 cifs_buf_release(pSMB);
6349
6350 if (rc == -EAGAIN)
6351 goto SetEARetry;
6352
6353 return rc;
6354}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355#endif