blob: 66d1ebfe75ddada9df891d2bc858d3371765fad1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080038#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070046#include "smbdirect.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#ifdef CONFIG_CIFS_POSIX
49static struct {
50 int index;
51 char *name;
52} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000053#ifdef CONFIG_CIFS_WEAK_PW_HASH
54 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000055 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000056#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000057 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000058 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 {BAD_PROT, "\2"}
60};
61#else
62static struct {
63 int index;
64 char *name;
65} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000066#ifdef CONFIG_CIFS_WEAK_PW_HASH
67 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000068 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000069#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000070 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 {BAD_PROT, "\2"}
72};
73#endif
74
Steve French39798772006-05-31 22:40:51 +000075/* define the number of elements in the cifs dialect array */
76#ifdef CONFIG_CIFS_POSIX
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 2
81#endif /* CIFS_WEAK_PW_HASH */
82#else /* not posix */
83#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000084#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000085#else
86#define CIFS_NUM_PROT 1
87#endif /* CONFIG_CIFS_WEAK_PW_HASH */
88#endif /* CIFS_POSIX */
89
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040090/*
91 * Mark as invalid, all open files on tree connections since they
92 * were closed when session to server was lost.
93 */
94void
95cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
97 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000098 struct list_head *tmp;
99 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400101 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500102 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400103 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000104 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000105 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400106 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 }
Steve French3afca262016-09-22 18:58:16 -0500108 spin_unlock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400109 /*
110 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
111 * to this tcon.
112 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113}
114
Jeff Layton9162ab22009-09-03 12:07:17 -0400115/* reconnect the socket, tcon, and smb session if needed */
116static int
Steve French96daf2b2011-05-27 04:34:02 +0000117cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400118{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400119 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000120 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400121 struct TCP_Server_Info *server;
122 struct nls_table *nls_codepage;
123
124 /*
125 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
126 * tcp and smb session status done differently for those three - in the
127 * calling routine
128 */
129 if (!tcon)
130 return 0;
131
132 ses = tcon->ses;
133 server = ses->server;
134
135 /*
136 * only tree disconnect, open, and write, (and ulogoff which does not
137 * have tcon) are allowed as we start force umount
138 */
139 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) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500143 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
144 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400145 return -ENODEV;
146 }
147 }
148
Jeff Layton9162ab22009-09-03 12:07:17 -0400149 /*
150 * Give demultiplex thread up to 10 seconds to reconnect, should be
151 * greater than cifs socket timeout which is 7 seconds
152 */
153 while (server->tcpStatus == CifsNeedReconnect) {
154 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000155 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400156
Steve Frenchfd88ce92011-04-12 01:01:14 +0000157 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400158 if (server->tcpStatus != CifsNeedReconnect)
159 break;
160
161 /*
162 * on "soft" mounts we wait once. Hard mounts keep
163 * retrying until process is killed or server comes
164 * back on-line
165 */
Jeff Laytond4025392011-02-07 08:54:35 -0500166 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500167 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400168 return -EHOSTDOWN;
169 }
170 }
171
172 if (!ses->need_reconnect && !tcon->need_reconnect)
173 return 0;
174
175 nls_codepage = load_nls_default();
176
177 /*
178 * need to prevent multiple threads trying to simultaneously
179 * reconnect the same SMB session
180 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000181 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200182
183 /*
184 * Recheck after acquire mutex. If another thread is negotiating
185 * and the server never sends an answer the socket will be closed
186 * and tcpStatus set to reconnect.
187 */
188 if (server->tcpStatus == CifsNeedReconnect) {
189 rc = -EHOSTDOWN;
190 mutex_unlock(&ses->session_mutex);
191 goto out;
192 }
193
Jeff Layton198b5682010-04-24 07:57:48 -0400194 rc = cifs_negotiate_protocol(0, ses);
195 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400196 rc = cifs_setup_session(0, ses, nls_codepage);
197
198 /* do we need to reconnect tcon? */
199 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000200 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400201 goto out;
202 }
203
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400204 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400205 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000206 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500207 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400208
209 if (rc)
210 goto out;
211
Jeff Layton9162ab22009-09-03 12:07:17 -0400212 atomic_inc(&tconInfoReconnectCount);
213
214 /* tell server Unix caps we support */
215 if (ses->capabilities & CAP_UNIX)
216 reset_cifs_unix_caps(0, tcon, NULL, NULL);
217
218 /*
219 * Removed call to reopen open files here. It is safer (and faster) to
220 * reopen files one at a time as needed in read and write.
221 *
222 * FIXME: what about file locks? don't we need to reclaim them ASAP?
223 */
224
225out:
226 /*
227 * Check if handle based operation so we know whether we can continue
228 * or not without returning to caller to reset file handle
229 */
230 switch (smb_command) {
231 case SMB_COM_READ_ANDX:
232 case SMB_COM_WRITE_ANDX:
233 case SMB_COM_CLOSE:
234 case SMB_COM_FIND_CLOSE2:
235 case SMB_COM_LOCKING_ANDX:
236 rc = -EAGAIN;
237 }
238
239 unload_nls(nls_codepage);
240 return rc;
241}
242
Steve Frenchad7a2922008-02-07 23:25:02 +0000243/* Allocate and return pointer to an SMB request buffer, and set basic
244 SMB information in the SMB header. If the return code is zero, this
245 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246static int
Steve French96daf2b2011-05-27 04:34:02 +0000247small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000248 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
Jeff Laytonf5695992010-09-29 15:27:08 -0400250 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Jeff Layton9162ab22009-09-03 12:07:17 -0400252 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000253 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 return rc;
255
256 *request_buf = cifs_small_buf_get();
257 if (*request_buf == NULL) {
258 /* BB should we add a retry in here if not a writepage? */
259 return -ENOMEM;
260 }
261
Steve French63135e02007-07-17 17:34:02 +0000262 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000263 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Steve French790fe572007-07-07 19:25:05 +0000265 if (tcon != NULL)
266 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700267
Jeff Laytonf5695992010-09-29 15:27:08 -0400268 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000269}
270
Steve French12b3b8f2006-02-09 21:12:47 +0000271int
Steve French50c2f752007-07-13 00:33:32 +0000272small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000273 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000274{
275 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000276 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000277
Steve French5815449d2006-02-14 01:36:20 +0000278 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000279 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000280 return rc;
281
Steve French04fdabe2006-02-10 05:52:50 +0000282 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400283 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000284 if (ses->capabilities & CAP_UNICODE)
285 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000286 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000287 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
288
289 /* uid, tid can stay at zero as set in header assemble */
290
Steve French50c2f752007-07-13 00:33:32 +0000291 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000292 this function is used after 1st of session setup requests */
293
294 return rc;
295}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297/* If the return code is zero, this function must fill in request_buf pointer */
298static int
Steve French96daf2b2011-05-27 04:34:02 +0000299__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400300 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 *request_buf = cifs_buf_get();
303 if (*request_buf == NULL) {
304 /* BB should we add a retry in here if not a writepage? */
305 return -ENOMEM;
306 }
307 /* Although the original thought was we needed the response buf for */
308 /* potential retries of smb operations it turns out we can determine */
309 /* from the mid flags when the request buffer can be resent without */
310 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000311 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000312 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000315 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Steve French790fe572007-07-07 19:25:05 +0000317 if (tcon != NULL)
318 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700319
Jeff Laytonf5695992010-09-29 15:27:08 -0400320 return 0;
321}
322
323/* If the return code is zero, this function must fill in request_buf pointer */
324static int
Steve French96daf2b2011-05-27 04:34:02 +0000325smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400326 void **request_buf, void **response_buf)
327{
328 int rc;
329
330 rc = cifs_reconnect_tcon(tcon, smb_command);
331 if (rc)
332 return rc;
333
334 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
335}
336
337static int
Steve French96daf2b2011-05-27 04:34:02 +0000338smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400339 void **request_buf, void **response_buf)
340{
341 if (tcon->ses->need_reconnect || tcon->need_reconnect)
342 return -EHOSTDOWN;
343
344 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345}
346
Steve French50c2f752007-07-13 00:33:32 +0000347static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
Jeff Layton12df83c2011-01-20 13:36:51 -0500349 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 /* check for plausible wct */
352 if (pSMB->hdr.WordCount < 10)
353 goto vt2_err;
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500356 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
357 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
358 goto vt2_err;
359
Jeff Layton12df83c2011-01-20 13:36:51 -0500360 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
361 if (total_size >= 512)
362 goto vt2_err;
363
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400364 /* check that bcc is at least as big as parms + data, and that it is
365 * less than negotiated smb buffer
366 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
368 if (total_size > get_bcc(&pSMB->hdr) ||
369 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
370 goto vt2_err;
371
372 return 0;
373vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000374 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500376 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
Jeff Layton690c5222011-01-20 13:36:51 -0500378
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400379static int
Jeff Layton3f618222013-06-12 19:52:14 -0500380decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400381{
382 int rc = 0;
383 u16 count;
384 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500385 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400386
387 count = get_bcc(&pSMBr->hdr);
388 if (count < SMB1_CLIENT_GUID_SIZE)
389 return -EIO;
390
391 spin_lock(&cifs_tcp_ses_lock);
392 if (server->srv_count > 1) {
393 spin_unlock(&cifs_tcp_ses_lock);
394 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
395 cifs_dbg(FYI, "server UID changed\n");
396 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
397 }
398 } else {
399 spin_unlock(&cifs_tcp_ses_lock);
400 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
401 }
402
403 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500404 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400405 } else {
406 count -= SMB1_CLIENT_GUID_SIZE;
407 rc = decode_negTokenInit(
408 pSMBr->u.extended_response.SecurityBlob, count, server);
409 if (rc != 1)
410 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400411 }
412
413 return 0;
414}
415
Jeff Layton9ddec562013-05-26 07:00:58 -0400416int
Jeff Layton38d77c52013-05-26 07:01:00 -0400417cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400418{
Jeff Layton502858822013-06-27 12:45:00 -0400419 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
420 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400421 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
422
423 /*
424 * Is signing required by mnt options? If not then check
425 * global_secflags to see if it is there.
426 */
427 if (!mnt_sign_required)
428 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
429 CIFSSEC_MUST_SIGN);
430
431 /*
432 * If signing is required then it's automatically enabled too,
433 * otherwise, check to see if the secflags allow it.
434 */
435 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
436 (global_secflags & CIFSSEC_MAY_SIGN);
437
438 /* If server requires signing, does client allow it? */
439 if (srv_sign_required) {
440 if (!mnt_sign_enabled) {
441 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
442 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400443 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400444 server->sign = true;
445 }
446
447 /* If client requires signing, does server allow it? */
448 if (mnt_sign_required) {
449 if (!srv_sign_enabled) {
450 cifs_dbg(VFS, "Server does not support signing!");
451 return -ENOTSUPP;
452 }
453 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400454 }
455
456 return 0;
457}
458
Jeff Layton2190eca2013-05-26 07:00:57 -0400459#ifdef CONFIG_CIFS_WEAK_PW_HASH
460static int
Jeff Layton3f618222013-06-12 19:52:14 -0500461decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400462{
463 __s16 tmp;
464 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
465
466 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
467 return -EOPNOTSUPP;
468
Jeff Layton2190eca2013-05-26 07:00:57 -0400469 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
470 server->maxReq = min_t(unsigned int,
471 le16_to_cpu(rsp->MaxMpxCount),
472 cifs_max_pending);
473 set_credits(server, server->maxReq);
474 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400475 /* even though we do not use raw we might as well set this
476 accurately, in case we ever find a need for it */
477 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
478 server->max_rw = 0xFF00;
479 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
480 } else {
481 server->max_rw = 0;/* do not need to use raw anyway */
482 server->capabilities = CAP_MPX_MODE;
483 }
484 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
485 if (tmp == -1) {
486 /* OS/2 often does not set timezone therefore
487 * we must use server time to calc time zone.
488 * Could deviate slightly from the right zone.
489 * Smallest defined timezone difference is 15 minutes
490 * (i.e. Nepal). Rounding up/down is done to match
491 * this requirement.
492 */
493 int val, seconds, remain, result;
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700494 struct timespec ts;
495 unsigned long utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400496 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
497 rsp->SrvTime.Time, 0);
498 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700499 (int)ts.tv_sec, (int)utc,
500 (int)(utc - ts.tv_sec));
501 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400502 seconds = abs(val);
503 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
504 remain = seconds % MIN_TZ_ADJ;
505 if (remain >= (MIN_TZ_ADJ / 2))
506 result += MIN_TZ_ADJ;
507 if (val < 0)
508 result = -result;
509 server->timeAdj = result;
510 } else {
511 server->timeAdj = (int)tmp;
512 server->timeAdj *= 60; /* also in seconds */
513 }
514 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
515
516
517 /* BB get server time for time conversions and add
518 code to use it and timezone since this is not UTC */
519
520 if (rsp->EncryptionKeyLength ==
521 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
522 memcpy(server->cryptkey, rsp->EncryptionKey,
523 CIFS_CRYPTO_KEY_SIZE);
524 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
525 return -EIO; /* need cryptkey unless plain text */
526 }
527
528 cifs_dbg(FYI, "LANMAN negotiated\n");
529 return 0;
530}
531#else
532static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500533decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400534{
535 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
536 return -EOPNOTSUPP;
537}
538#endif
539
Jeff Layton91934002013-05-26 07:00:58 -0400540static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500541should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400542{
Jeff Layton3f618222013-06-12 19:52:14 -0500543 switch (sectype) {
544 case RawNTLMSSP:
545 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400546 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500547 case Unspecified:
548 if (global_secflags &
549 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
550 return true;
551 /* Fallthrough */
552 default:
553 return false;
554 }
Jeff Layton91934002013-05-26 07:00:58 -0400555}
556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400558CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
560 NEGOTIATE_REQ *pSMB;
561 NEGOTIATE_RSP *pSMBr;
562 int rc = 0;
563 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000564 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400565 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 u16 count;
567
Jeff Layton3534b852013-05-24 07:41:01 -0400568 if (!server) {
569 WARN(1, "%s: server is NULL!\n", __func__);
570 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
Jeff Layton3534b852013-05-24 07:41:01 -0400572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
574 (void **) &pSMB, (void **) &pSMBr);
575 if (rc)
576 return rc;
Steve French750d1152006-06-27 06:28:30 +0000577
Pavel Shilovsky88257362012-05-23 14:01:59 +0400578 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000579 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000580
Jeff Layton3f618222013-06-12 19:52:14 -0500581 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400582 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000583 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
584 }
Steve French50c2f752007-07-13 00:33:32 +0000585
Steve French39798772006-05-31 22:40:51 +0000586 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000587 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000588 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
589 count += strlen(protocols[i].name) + 1;
590 /* null at end of source and target buffers anyway */
591 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000592 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 pSMB->ByteCount = cpu_to_le16(count);
594
595 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000597 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000598 goto neg_err_exit;
599
Jeff Layton9bf67e52010-04-24 07:57:46 -0400600 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500601 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000602 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400603 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000604 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000605 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000606 could not negotiate a common dialect */
607 rc = -EOPNOTSUPP;
608 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000609 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400610 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500611 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400612 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000613 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000614 /* unknown wct */
615 rc = -EOPNOTSUPP;
616 goto neg_err_exit;
617 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400618 /* else wct == 17, NTLM or better */
619
Steve French96daf2b2011-05-27 04:34:02 +0000620 server->sec_mode = pSMBr->SecurityMode;
621 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500622 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000623
Steve French254e55e2006-06-04 05:53:15 +0000624 /* one byte, so no need to convert this or EncryptionKeyLen from
625 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300626 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
627 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400628 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000629 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400630 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000631 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500632 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000633 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000634 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
635 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400636
Jeff Laytone598d1d82013-05-26 07:00:59 -0400637 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
638 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500639 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000640 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100641 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
642 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400643 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500644 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400645 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000646 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400647 } else {
648 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000649 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400650 }
Steve French254e55e2006-06-04 05:53:15 +0000651
652signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400653 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400654 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000655neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700656 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000657
Joe Perchesf96637b2013-05-04 22:12:25 -0500658 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 return rc;
660}
661
662int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400663CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Joe Perchesf96637b2013-05-04 22:12:25 -0500668 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500669
670 /* BB: do we need to check this? These should never be NULL. */
671 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
672 return -EIO;
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675 * No need to return error on this operation if tid invalidated and
676 * closed on server already e.g. due to tcp session crashing. Also,
677 * the tcon is no longer on the list, so no need to take lock before
678 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 */
Steve French268875b2009-06-25 00:29:21 +0000680 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Steve French50c2f752007-07-13 00:33:32 +0000683 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700684 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500685 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return rc;
Steve French133672e2007-11-13 22:41:37 +0000687
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400688 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700689 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500691 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Steve French50c2f752007-07-13 00:33:32 +0000693 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500694 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc == -EAGAIN)
696 rc = 0;
697
698 return rc;
699}
700
Jeff Layton766fdbb2011-01-11 07:24:21 -0500701/*
702 * This is a no-op for now. We're not really interested in the reply, but
703 * rather in the fact that the server sent one and that server->lstrp
704 * gets updated.
705 *
706 * FIXME: maybe we should consider checking that the reply matches request?
707 */
708static void
709cifs_echo_callback(struct mid_q_entry *mid)
710{
711 struct TCP_Server_Info *server = mid->callback_data;
712
713 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400714 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500715}
716
717int
718CIFSSMBEcho(struct TCP_Server_Info *server)
719{
720 ECHO_REQ *smb;
721 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800722 struct kvec iov[2];
723 struct smb_rqst rqst = { .rq_iov = iov,
724 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725
Joe Perchesf96637b2013-05-04 22:12:25 -0500726 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500727
728 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
729 if (rc)
730 return rc;
731
Steve French26c9cb62017-05-02 13:35:20 -0500732 if (server->capabilities & CAP_UNICODE)
733 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
734
Jeff Layton766fdbb2011-01-11 07:24:21 -0500735 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000736 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500737 smb->hdr.WordCount = 1;
738 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400739 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500740 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000741 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800742
743 iov[0].iov_len = 4;
744 iov[0].iov_base = smb;
745 iov[1].iov_len = get_rfc1002_length(smb);
746 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500747
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800748 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400749 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500750 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500751 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500752
753 cifs_small_buf_release(smb);
754
755 return rc;
756}
757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400759CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 LOGOFF_ANDX_REQ *pSMB;
762 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Joe Perchesf96637b2013-05-04 22:12:25 -0500764 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500765
766 /*
767 * BB: do we need to check validity of ses and server? They should
768 * always be valid since we have an active reference. If not, that
769 * should probably be a BUG()
770 */
771 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return -EIO;
773
Steve Frenchd7b619c2010-02-25 05:36:46 +0000774 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000775 if (ses->need_reconnect)
776 goto session_already_dead; /* no need to send SMBlogoff if uid
777 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
779 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000780 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 return rc;
782 }
783
Pavel Shilovsky88257362012-05-23 14:01:59 +0400784 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700785
Jeff Layton38d77c52013-05-26 07:01:00 -0400786 if (ses->server->sign)
787 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 pSMB->hdr.Uid = ses->Suid;
790
791 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400792 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700793 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000794session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000795 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000798 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 error */
800 if (rc == -EAGAIN)
801 rc = 0;
802 return rc;
803}
804
805int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400806CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
807 const char *fileName, __u16 type,
808 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000809{
810 TRANSACTION2_SPI_REQ *pSMB = NULL;
811 TRANSACTION2_SPI_RSP *pSMBr = NULL;
812 struct unlink_psx_rq *pRqD;
813 int name_len;
814 int rc = 0;
815 int bytes_returned = 0;
816 __u16 params, param_offset, offset, byte_count;
817
Joe Perchesf96637b2013-05-04 22:12:25 -0500818 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000819PsxDelete:
820 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
821 (void **) &pSMBr);
822 if (rc)
823 return rc;
824
825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
826 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600827 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
828 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000829 name_len++; /* trailing null */
830 name_len *= 2;
831 } else { /* BB add path length overrun check */
832 name_len = strnlen(fileName, PATH_MAX);
833 name_len++; /* trailing null */
834 strncpy(pSMB->FileName, fileName, name_len);
835 }
836
837 params = 6 + name_len;
838 pSMB->MaxParameterCount = cpu_to_le16(2);
839 pSMB->MaxDataCount = 0; /* BB double check this with jra */
840 pSMB->MaxSetupCount = 0;
841 pSMB->Reserved = 0;
842 pSMB->Flags = 0;
843 pSMB->Timeout = 0;
844 pSMB->Reserved2 = 0;
845 param_offset = offsetof(struct smb_com_transaction2_spi_req,
846 InformationLevel) - 4;
847 offset = param_offset + params;
848
849 /* Setup pointer to Request Data (inode type) */
850 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
851 pRqD->type = cpu_to_le16(type);
852 pSMB->ParameterOffset = cpu_to_le16(param_offset);
853 pSMB->DataOffset = cpu_to_le16(offset);
854 pSMB->SetupCount = 1;
855 pSMB->Reserved3 = 0;
856 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
857 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
858
859 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
860 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
861 pSMB->ParameterCount = cpu_to_le16(params);
862 pSMB->TotalParameterCount = pSMB->ParameterCount;
863 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
864 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000865 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000866 pSMB->ByteCount = cpu_to_le16(byte_count);
867 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
868 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000869 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500870 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000871 cifs_buf_release(pSMB);
872
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400873 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000874
875 if (rc == -EAGAIN)
876 goto PsxDelete;
877
878 return rc;
879}
880
881int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700882CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
883 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 DELETE_FILE_REQ *pSMB = NULL;
886 DELETE_FILE_RSP *pSMBr = NULL;
887 int rc = 0;
888 int bytes_returned;
889 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500890 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892DelFileRetry:
893 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
894 (void **) &pSMBr);
895 if (rc)
896 return rc;
897
898 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700899 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
900 PATH_MAX, cifs_sb->local_nls,
901 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 name_len++; /* trailing null */
903 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700904 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700905 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700907 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
909 pSMB->SearchAttributes =
910 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
911 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000912 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 pSMB->ByteCount = cpu_to_le16(name_len + 1);
914 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
915 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400916 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000917 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500918 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920 cifs_buf_release(pSMB);
921 if (rc == -EAGAIN)
922 goto DelFileRetry;
923
924 return rc;
925}
926
927int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400928CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
929 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930{
931 DELETE_DIRECTORY_REQ *pSMB = NULL;
932 DELETE_DIRECTORY_RSP *pSMBr = NULL;
933 int rc = 0;
934 int bytes_returned;
935 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500936 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Joe Perchesf96637b2013-05-04 22:12:25 -0500938 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939RmDirRetry:
940 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
941 (void **) &pSMBr);
942 if (rc)
943 return rc;
944
945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400946 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
947 PATH_MAX, cifs_sb->local_nls,
948 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 name_len++; /* trailing null */
950 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700951 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400952 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400954 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 }
956
957 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000958 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 pSMB->ByteCount = cpu_to_le16(name_len + 1);
960 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400962 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000963 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500964 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 cifs_buf_release(pSMB);
967 if (rc == -EAGAIN)
968 goto RmDirRetry;
969 return rc;
970}
971
972int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300973CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
974 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
976 int rc = 0;
977 CREATE_DIRECTORY_REQ *pSMB = NULL;
978 CREATE_DIRECTORY_RSP *pSMBr = NULL;
979 int bytes_returned;
980 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500981 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Joe Perchesf96637b2013-05-04 22:12:25 -0500983 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984MkDirRetry:
985 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
986 (void **) &pSMBr);
987 if (rc)
988 return rc;
989
990 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600991 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300992 PATH_MAX, cifs_sb->local_nls,
993 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 name_len++; /* trailing null */
995 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700996 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 name_len = strnlen(name, PATH_MAX);
998 name_len++; /* trailing null */
999 strncpy(pSMB->DirName, name, name_len);
1000 }
1001
1002 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001003 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001007 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001008 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001009 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 cifs_buf_release(pSMB);
1012 if (rc == -EAGAIN)
1013 goto MkDirRetry;
1014 return rc;
1015}
1016
Steve French2dd29d32007-04-23 22:07:35 +00001017int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001018CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1019 __u32 posix_flags, __u64 mode, __u16 *netfid,
1020 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1021 const char *name, const struct nls_table *nls_codepage,
1022 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001023{
1024 TRANSACTION2_SPI_REQ *pSMB = NULL;
1025 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1026 int name_len;
1027 int rc = 0;
1028 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001029 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001030 OPEN_PSX_REQ *pdata;
1031 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001032
Joe Perchesf96637b2013-05-04 22:12:25 -05001033 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001034PsxCreat:
1035 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1036 (void **) &pSMBr);
1037 if (rc)
1038 return rc;
1039
1040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1041 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001042 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1043 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001044 name_len++; /* trailing null */
1045 name_len *= 2;
1046 } else { /* BB improve the check for buffer overruns BB */
1047 name_len = strnlen(name, PATH_MAX);
1048 name_len++; /* trailing null */
1049 strncpy(pSMB->FileName, name, name_len);
1050 }
1051
1052 params = 6 + name_len;
1053 count = sizeof(OPEN_PSX_REQ);
1054 pSMB->MaxParameterCount = cpu_to_le16(2);
1055 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1056 pSMB->MaxSetupCount = 0;
1057 pSMB->Reserved = 0;
1058 pSMB->Flags = 0;
1059 pSMB->Timeout = 0;
1060 pSMB->Reserved2 = 0;
1061 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001062 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001063 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001064 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001065 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001066 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001067 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001068 pdata->OpenFlags = cpu_to_le32(*pOplock);
1069 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1070 pSMB->DataOffset = cpu_to_le16(offset);
1071 pSMB->SetupCount = 1;
1072 pSMB->Reserved3 = 0;
1073 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1074 byte_count = 3 /* pad */ + params + count;
1075
1076 pSMB->DataCount = cpu_to_le16(count);
1077 pSMB->ParameterCount = cpu_to_le16(params);
1078 pSMB->TotalDataCount = pSMB->DataCount;
1079 pSMB->TotalParameterCount = pSMB->ParameterCount;
1080 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1081 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001082 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001083 pSMB->ByteCount = cpu_to_le16(byte_count);
1084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1086 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001087 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001088 goto psx_create_err;
1089 }
1090
Joe Perchesf96637b2013-05-04 22:12:25 -05001091 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001092 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1093
Jeff Layton820a8032011-05-04 08:05:26 -04001094 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001095 rc = -EIO; /* bad smb */
1096 goto psx_create_err;
1097 }
1098
1099 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001100 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001101 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001102
Steve French2dd29d32007-04-23 22:07:35 +00001103 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001104 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001105 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1106 /* Let caller know file was created so we can set the mode. */
1107 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001108 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001109 *pOplock |= CIFS_CREATE_ACTION;
1110 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001111 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1112 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001113 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001114 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001115 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001116 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001117 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001118 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001119 goto psx_create_err;
1120 }
Steve French50c2f752007-07-13 00:33:32 +00001121 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001122 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001123 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001124 }
Steve French2dd29d32007-04-23 22:07:35 +00001125
1126psx_create_err:
1127 cifs_buf_release(pSMB);
1128
Steve French65bc98b2009-07-10 15:27:25 +00001129 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001130 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001131 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001132 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001133
1134 if (rc == -EAGAIN)
1135 goto PsxCreat;
1136
Steve French50c2f752007-07-13 00:33:32 +00001137 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001138}
1139
Steve Frencha9d02ad2005-08-24 23:06:05 -07001140static __u16 convert_disposition(int disposition)
1141{
1142 __u16 ofun = 0;
1143
1144 switch (disposition) {
1145 case FILE_SUPERSEDE:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1147 break;
1148 case FILE_OPEN:
1149 ofun = SMBOPEN_OAPPEND;
1150 break;
1151 case FILE_CREATE:
1152 ofun = SMBOPEN_OCREATE;
1153 break;
1154 case FILE_OPEN_IF:
1155 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1156 break;
1157 case FILE_OVERWRITE:
1158 ofun = SMBOPEN_OTRUNC;
1159 break;
1160 case FILE_OVERWRITE_IF:
1161 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1162 break;
1163 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001164 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001165 ofun = SMBOPEN_OAPPEND; /* regular open */
1166 }
1167 return ofun;
1168}
1169
Jeff Layton35fc37d2008-05-14 10:22:03 -07001170static int
1171access_flags_to_smbopen_mode(const int access_flags)
1172{
1173 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1174
1175 if (masked_flags == GENERIC_READ)
1176 return SMBOPEN_READ;
1177 else if (masked_flags == GENERIC_WRITE)
1178 return SMBOPEN_WRITE;
1179
1180 /* just go for read/write */
1181 return SMBOPEN_READWRITE;
1182}
1183
Steve Frencha9d02ad2005-08-24 23:06:05 -07001184int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001185SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001187 const int access_flags, const int create_options, __u16 *netfid,
1188 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001189 const struct nls_table *nls_codepage, int remap)
1190{
1191 int rc = -EACCES;
1192 OPENX_REQ *pSMB = NULL;
1193 OPENX_RSP *pSMBr = NULL;
1194 int bytes_returned;
1195 int name_len;
1196 __u16 count;
1197
1198OldOpenRetry:
1199 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1200 (void **) &pSMBr);
1201 if (rc)
1202 return rc;
1203
1204 pSMB->AndXCommand = 0xFF; /* none */
1205
1206 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1207 count = 1; /* account for one byte pad to word boundary */
1208 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001209 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1210 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 name_len++; /* trailing null */
1212 name_len *= 2;
1213 } else { /* BB improve check for buffer overruns BB */
1214 count = 0; /* no pad */
1215 name_len = strnlen(fileName, PATH_MAX);
1216 name_len++; /* trailing null */
1217 strncpy(pSMB->fileName, fileName, name_len);
1218 }
1219 if (*pOplock & REQ_OPLOCK)
1220 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001221 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001223
Steve Frencha9d02ad2005-08-24 23:06:05 -07001224 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001225 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1227 /* set file as system file if special file such
1228 as fifo and server expecting SFU style and
1229 no Unix extensions */
1230
Steve French790fe572007-07-07 19:25:05 +00001231 if (create_options & CREATE_OPTION_SPECIAL)
1232 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001233 else /* BB FIXME BB */
1234 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235
Jeff Layton67750fb2008-05-09 22:28:02 +00001236 if (create_options & CREATE_OPTION_READONLY)
1237 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238
1239 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001240/* pSMB->CreateOptions = cpu_to_le32(create_options &
1241 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001243
1244 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001245 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001247 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248
1249 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001251 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001252 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001254 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 } else {
1256 /* BB verify if wct == 15 */
1257
Steve French582d21e2008-05-13 04:54:12 +00001258/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1261 /* Let caller know file was created so we can set the mode. */
1262 /* Do we care about the CreateAction in any other cases? */
1263 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001264/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 *pOplock |= CIFS_CREATE_ACTION; */
1266 /* BB FIXME END */
1267
Steve French790fe572007-07-07 19:25:05 +00001268 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270 pfile_info->LastAccessTime = 0; /* BB fixme */
1271 pfile_info->LastWriteTime = 0; /* BB fixme */
1272 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001273 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001274 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001276 pfile_info->AllocationSize =
1277 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001280 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 }
1282 }
1283
1284 cifs_buf_release(pSMB);
1285 if (rc == -EAGAIN)
1286 goto OldOpenRetry;
1287 return rc;
1288}
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001291CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1292 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293{
1294 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001295 OPEN_REQ *req = NULL;
1296 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 int bytes_returned;
1298 int name_len;
1299 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001300 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1301 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001302 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001303 const struct nls_table *nls = cifs_sb->local_nls;
1304 int create_options = oparms->create_options;
1305 int desired_access = oparms->desired_access;
1306 int disposition = oparms->disposition;
1307 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001310 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1311 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 if (rc)
1313 return rc;
1314
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001315 /* no commands go after this */
1316 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001318 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1319 /* account for one byte pad to word boundary */
1320 count = 1;
1321 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1322 path, PATH_MAX, nls, remap);
1323 /* trailing null */
1324 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001326 req->NameLength = cpu_to_le16(name_len);
1327 } else {
1328 /* BB improve check for buffer overruns BB */
1329 /* no pad */
1330 count = 0;
1331 name_len = strnlen(path, PATH_MAX);
1332 /* trailing null */
1333 name_len++;
1334 req->NameLength = cpu_to_le16(name_len);
1335 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001337
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001338 if (*oplock & REQ_OPLOCK)
1339 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1340 else if (*oplock & REQ_BATCHOPLOCK)
1341 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1342
1343 req->DesiredAccess = cpu_to_le32(desired_access);
1344 req->AllocationSize = 0;
1345
1346 /*
1347 * Set file as system file if special file such as fifo and server
1348 * expecting SFU style and no Unix extensions.
1349 */
1350 if (create_options & CREATE_OPTION_SPECIAL)
1351 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1352 else
1353 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1354
1355 /*
1356 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1357 * sensitive checks for other servers such as Samba.
1358 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001360 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Jeff Layton67750fb2008-05-09 22:28:02 +00001362 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001363 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001364
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001365 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1366 req->CreateDisposition = cpu_to_le32(disposition);
1367 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1368
Steve French09d1db52005-04-28 22:41:08 -07001369 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001370 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1371 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
1373 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001374 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001376 req->ByteCount = cpu_to_le16(count);
1377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1378 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001379 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001381 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001382 cifs_buf_release(req);
1383 if (rc == -EAGAIN)
1384 goto openRetry;
1385 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001387
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001388 /* 1 byte no need to le_to_cpu */
1389 *oplock = rsp->OplockLevel;
1390 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001391 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001392
1393 /* Let caller know file was created so we can set the mode. */
1394 /* Do we care about the CreateAction in any other cases? */
1395 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1396 *oplock |= CIFS_CREATE_ACTION;
1397
1398 if (buf) {
1399 /* copy from CreationTime to Attributes */
1400 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1401 /* the file_info buf is endian converted by caller */
1402 buf->AllocationSize = rsp->AllocationSize;
1403 buf->EndOfFile = rsp->EndOfFile;
1404 buf->NumberOfLinks = cpu_to_le32(1);
1405 buf->DeletePending = 0;
1406 }
1407
1408 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return rc;
1410}
1411
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001412/*
1413 * Discard any remaining data in the current SMB. To do this, we borrow the
1414 * current bigbuf.
1415 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001416int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001417cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001418{
Pavel Shilovsky350be252017-04-10 10:31:33 -07001419 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001420 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001421
1422 while (remaining > 0) {
1423 int length;
1424
1425 length = cifs_read_from_socket(server, server->bigbuf,
1426 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001427 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001428 if (length < 0)
1429 return length;
1430 server->total_read += length;
1431 remaining -= length;
1432 }
1433
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001434 return 0;
1435}
1436
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001437static int
1438cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1439{
1440 int length;
1441 struct cifs_readdata *rdata = mid->callback_data;
1442
Pavel Shilovsky350be252017-04-10 10:31:33 -07001443 length = cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001444 dequeue_mid(mid, rdata->result);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001445 mid->resp_buf = server->smallbuf;
1446 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001447 return length;
1448}
1449
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001450int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1452{
1453 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001454 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001455 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001456 char *buf = server->smallbuf;
1457 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001458
Joe Perchesf96637b2013-05-04 22:12:25 -05001459 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1460 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001461
1462 /*
1463 * read the rest of READ_RSP header (sans Data array), or whatever we
1464 * can if there's not enough data. At this point, we've read down to
1465 * the Mid.
1466 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001467 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001468 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001469
Al Viroa6137302016-01-09 19:37:16 -05001470 length = cifs_read_from_socket(server,
1471 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001472 if (length < 0)
1473 return length;
1474 server->total_read += length;
1475
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001476 if (server->ops->is_session_expired &&
1477 server->ops->is_session_expired(buf)) {
1478 cifs_reconnect(server);
1479 wake_up(&server->response_q);
1480 return -1;
1481 }
1482
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001483 if (server->ops->is_status_pending &&
1484 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001485 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001486 return -1;
1487 }
1488
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001490 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001491 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001492 cifs_dbg(FYI, "%s: server returned error %d\n",
1493 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001494 return cifs_readv_discard(server, mid);
1495 }
1496
1497 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001498 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001499 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1500 __func__, server->total_read,
1501 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001502 rdata->result = -EIO;
1503 return cifs_readv_discard(server, mid);
1504 }
1505
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001506 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001507 if (data_offset < server->total_read) {
1508 /*
1509 * win2k8 sometimes sends an offset of 0 when the read
1510 * is beyond the EOF. Treat it as if the data starts just after
1511 * the header.
1512 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001513 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1514 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001515 data_offset = server->total_read;
1516 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1517 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001518 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1519 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520 rdata->result = -EIO;
1521 return cifs_readv_discard(server, mid);
1522 }
1523
Joe Perchesf96637b2013-05-04 22:12:25 -05001524 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1525 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001526
1527 len = data_offset - server->total_read;
1528 if (len > 0) {
1529 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001530 length = cifs_read_from_socket(server,
1531 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001532 if (length < 0)
1533 return length;
1534 server->total_read += length;
1535 }
1536
1537 /* set up first iov for signature check */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001538 rdata->iov[0].iov_base = buf;
1539 rdata->iov[0].iov_len = 4;
1540 rdata->iov[1].iov_base = buf + 4;
1541 rdata->iov[1].iov_len = server->total_read - 4;
1542 cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
1543 rdata->iov[0].iov_base, server->total_read);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001544
1545 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001546 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001547 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001548 /* data_len is corrupt -- discard frame */
1549 rdata->result = -EIO;
1550 return cifs_readv_discard(server, mid);
1551 }
1552
Jeff Layton8321fec2012-09-19 06:22:32 -07001553 length = rdata->read_into_pages(server, rdata, data_len);
1554 if (length < 0)
1555 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556
Jeff Layton8321fec2012-09-19 06:22:32 -07001557 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558
Joe Perchesf96637b2013-05-04 22:12:25 -05001559 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1560 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001561
1562 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001563 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001564 return cifs_readv_discard(server, mid);
1565
1566 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001567 mid->resp_buf = server->smallbuf;
1568 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001569 return length;
1570}
1571
1572static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573cifs_readv_callback(struct mid_q_entry *mid)
1574{
1575 struct cifs_readdata *rdata = mid->callback_data;
1576 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1577 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001578 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1579 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001580 .rq_pages = rdata->pages,
1581 .rq_npages = rdata->nr_pages,
1582 .rq_pagesz = rdata->pagesz,
1583 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001584
Joe Perchesf96637b2013-05-04 22:12:25 -05001585 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1586 __func__, mid->mid, mid->mid_state, rdata->result,
1587 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001588
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001589 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001590 case MID_RESPONSE_RECEIVED:
1591 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001592 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001593 int rc = 0;
1594
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001595 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001596 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001597 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001598 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1599 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001600 }
1601 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001602 task_io_account_read(rdata->got_bytes);
1603 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001604 break;
1605 case MID_REQUEST_SUBMITTED:
1606 case MID_RETRY_NEEDED:
1607 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001608 if (server->sign && rdata->got_bytes)
1609 /* reset bytes number since we can not check a sign */
1610 rdata->got_bytes = 0;
1611 /* FIXME: should this be counted toward the initiating task? */
1612 task_io_account_read(rdata->got_bytes);
1613 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001614 break;
1615 default:
1616 rdata->result = -EIO;
1617 }
1618
Jeff Laytonda472fc2012-03-23 14:40:53 -04001619 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001620 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001621 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001622}
1623
1624/* cifs_async_readv - send an async write, and set up mid to handle result */
1625int
1626cifs_async_readv(struct cifs_readdata *rdata)
1627{
1628 int rc;
1629 READ_REQ *smb = NULL;
1630 int wct;
1631 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001632 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1633 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001634
Joe Perchesf96637b2013-05-04 22:12:25 -05001635 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1636 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001637
1638 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1639 wct = 12;
1640 else {
1641 wct = 10; /* old style read */
1642 if ((rdata->offset >> 32) > 0) {
1643 /* can not handle this big offset for old */
1644 return -EIO;
1645 }
1646 }
1647
1648 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1649 if (rc)
1650 return rc;
1651
1652 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1653 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1654
1655 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001656 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001657 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1658 if (wct == 12)
1659 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1660 smb->Remaining = 0;
1661 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1662 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1663 if (wct == 12)
1664 smb->ByteCount = 0;
1665 else {
1666 /* old style read */
1667 struct smb_com_readx_req *smbr =
1668 (struct smb_com_readx_req *)smb;
1669 smbr->ByteCount = 0;
1670 }
1671
1672 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001673 rdata->iov[0].iov_base = smb;
1674 rdata->iov[0].iov_len = 4;
1675 rdata->iov[1].iov_base = (char *)smb + 4;
1676 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001677
Jeff Layton6993f742012-05-16 07:13:17 -04001678 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001679 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001680 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001681
1682 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001683 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001684 else
1685 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001686
1687 cifs_small_buf_release(smb);
1688 return rc;
1689}
1690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001692CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1693 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
1695 int rc = -EACCES;
1696 READ_REQ *pSMB = NULL;
1697 READ_RSP *pSMBr = NULL;
1698 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001699 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001700 int resp_buf_type = 0;
1701 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001702 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001703 __u32 pid = io_parms->pid;
1704 __u16 netfid = io_parms->netfid;
1705 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001706 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001707 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Joe Perchesf96637b2013-05-04 22:12:25 -05001709 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001710 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001711 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001712 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001713 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001714 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001715 /* can not handle this big offset for old */
1716 return -EIO;
1717 }
1718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
1720 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001721 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 if (rc)
1723 return rc;
1724
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001725 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1726 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1727
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 /* tcon and ses pointer are checked in smb_init */
1729 if (tcon->ses->server == NULL)
1730 return -ECONNABORTED;
1731
Steve Frenchec637e32005-12-12 20:53:18 -08001732 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001734 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001735 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001736 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001737
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 pSMB->Remaining = 0;
1739 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1740 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001741 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001742 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1743 else {
1744 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001745 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001746 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001747 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001748 }
Steve Frenchec637e32005-12-12 20:53:18 -08001749
1750 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001751 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001752 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1753 CIFS_LOG_ERROR, &rsp_iov);
1754 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001755 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001756 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001758 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 } else {
1760 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1761 data_length = data_length << 16;
1762 data_length += le16_to_cpu(pSMBr->DataLength);
1763 *nbytes = data_length;
1764
1765 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001766 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001768 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001769 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 rc = -EIO;
1771 *nbytes = 0;
1772 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001773 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001774 le16_to_cpu(pSMBr->DataOffset);
1775/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001776 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001777 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001778 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001779 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001780 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 }
1782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
Steve French790fe572007-07-07 19:25:05 +00001784 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001785 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001786 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001787 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001788 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001789 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001790 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001791 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001792 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001793 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001794
1795 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 since file handle passed in no longer valid */
1797 return rc;
1798}
1799
Steve Frenchec637e32005-12-12 20:53:18 -08001800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001802CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001803 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804{
1805 int rc = -EACCES;
1806 WRITE_REQ *pSMB = NULL;
1807 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001808 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 __u32 bytes_sent;
1810 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001811 __u32 pid = io_parms->pid;
1812 __u16 netfid = io_parms->netfid;
1813 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001814 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001815 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
Steve Frencha24e2d72010-04-03 17:20:21 +00001817 *nbytes = 0;
1818
Joe Perchesf96637b2013-05-04 22:12:25 -05001819 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001820 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001821 return -ECONNABORTED;
1822
Steve French790fe572007-07-07 19:25:05 +00001823 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001824 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001825 else {
Steve French1c955182005-08-30 20:58:07 -07001826 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001827 if ((offset >> 32) > 0) {
1828 /* can not handle big offset for old srv */
1829 return -EIO;
1830 }
1831 }
Steve French1c955182005-08-30 20:58:07 -07001832
1833 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 (void **) &pSMBr);
1835 if (rc)
1836 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001837
1838 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1839 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 /* tcon and ses pointer are checked in smb_init */
1842 if (tcon->ses->server == NULL)
1843 return -ECONNABORTED;
1844
1845 pSMB->AndXCommand = 0xFF; /* none */
1846 pSMB->Fid = netfid;
1847 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001848 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001849 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001850
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 pSMB->Reserved = 0xFFFFFFFF;
1852 pSMB->WriteMode = 0;
1853 pSMB->Remaining = 0;
1854
Steve French50c2f752007-07-13 00:33:32 +00001855 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 can send more if LARGE_WRITE_X capability returned by the server and if
1857 our buffer is big enough or if we convert to iovecs on socket writes
1858 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001859 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1861 } else {
1862 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1863 & ~0xFF;
1864 }
1865
1866 if (bytes_sent > count)
1867 bytes_sent = count;
1868 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001869 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001870 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001871 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001872 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 /* No buffer */
1874 cifs_buf_release(pSMB);
1875 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001876 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001877 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001878 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001879 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001880 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1883 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001884 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001885
Steve French790fe572007-07-07 19:25:05 +00001886 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001887 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001888 else { /* old style write has byte count 4 bytes earlier
1889 so 4 bytes pad */
1890 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001891 (struct smb_com_writex_req *)pSMB;
1892 pSMBW->ByteCount = cpu_to_le16(byte_count);
1893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
1895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001897 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001899 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 } else {
1901 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1902 *nbytes = (*nbytes) << 16;
1903 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301904
1905 /*
1906 * Mask off high 16 bits when bytes written as returned by the
1907 * server is greater than bytes requested by the client. Some
1908 * OS/2 servers are known to set incorrect CountHigh values.
1909 */
1910 if (*nbytes > count)
1911 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 }
1913
1914 cifs_buf_release(pSMB);
1915
Steve French50c2f752007-07-13 00:33:32 +00001916 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 since file handle passed in no longer valid */
1918
1919 return rc;
1920}
1921
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001922void
1923cifs_writedata_release(struct kref *refcount)
1924{
1925 struct cifs_writedata *wdata = container_of(refcount,
1926 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001927#ifdef CONFIG_CIFS_SMB_DIRECT
1928 if (wdata->mr) {
1929 smbd_deregister_mr(wdata->mr);
1930 wdata->mr = NULL;
1931 }
1932#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001933
1934 if (wdata->cfile)
1935 cifsFileInfo_put(wdata->cfile);
1936
1937 kfree(wdata);
1938}
1939
1940/*
1941 * Write failed with a retryable error. Resend the write request. It's also
1942 * possible that the page was redirtied so re-clean the page.
1943 */
1944static void
1945cifs_writev_requeue(struct cifs_writedata *wdata)
1946{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001947 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001948 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001949 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001950 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001951
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001952 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1953 i = 0;
1954 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001955 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001956 struct cifs_writedata *wdata2;
1957 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001958
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001959 wsize = server->ops->wp_retry_size(inode);
1960 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001961 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001962 if (!nr_pages) {
1963 rc = -ENOTSUPP;
1964 break;
1965 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001966 cur_len = nr_pages * PAGE_SIZE;
1967 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001968 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001969 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001970 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001971 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001972 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001973
1974 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1975 if (!wdata2) {
1976 rc = -ENOMEM;
1977 break;
1978 }
1979
1980 for (j = 0; j < nr_pages; j++) {
1981 wdata2->pages[j] = wdata->pages[i + j];
1982 lock_page(wdata2->pages[j]);
1983 clear_page_dirty_for_io(wdata2->pages[j]);
1984 }
1985
1986 wdata2->sync_mode = wdata->sync_mode;
1987 wdata2->nr_pages = nr_pages;
1988 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001989 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001990 wdata2->tailsz = tailsz;
1991 wdata2->bytes = cur_len;
1992
1993 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1994 if (!wdata2->cfile) {
1995 cifs_dbg(VFS, "No writable handles for inode\n");
1996 rc = -EBADF;
1997 break;
1998 }
1999 wdata2->pid = wdata2->cfile->pid;
2000 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2001
2002 for (j = 0; j < nr_pages; j++) {
2003 unlock_page(wdata2->pages[j]);
2004 if (rc != 0 && rc != -EAGAIN) {
2005 SetPageError(wdata2->pages[j]);
2006 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002007 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002008 }
2009 }
2010
2011 if (rc) {
2012 kref_put(&wdata2->refcount, cifs_writedata_release);
2013 if (rc == -EAGAIN)
2014 continue;
2015 break;
2016 }
2017
2018 rest_len -= cur_len;
2019 i += nr_pages;
2020 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002021
2022 mapping_set_error(inode->i_mapping, rc);
2023 kref_put(&wdata->refcount, cifs_writedata_release);
2024}
2025
Jeff Laytonc2e87642012-03-23 14:40:55 -04002026void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002027cifs_writev_complete(struct work_struct *work)
2028{
2029 struct cifs_writedata *wdata = container_of(work,
2030 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002031 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002032 int i = 0;
2033
2034 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002035 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002036 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002037 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002038 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2039 wdata->bytes);
2040 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2041 return cifs_writev_requeue(wdata);
2042
2043 for (i = 0; i < wdata->nr_pages; i++) {
2044 struct page *page = wdata->pages[i];
2045 if (wdata->result == -EAGAIN)
2046 __set_page_dirty_nobuffers(page);
2047 else if (wdata->result < 0)
2048 SetPageError(page);
2049 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002050 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002051 }
2052 if (wdata->result != -EAGAIN)
2053 mapping_set_error(inode->i_mapping, wdata->result);
2054 kref_put(&wdata->refcount, cifs_writedata_release);
2055}
2056
2057struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002058cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002059{
2060 struct cifs_writedata *wdata;
2061
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 /* writedata + number of page pointers */
2063 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002064 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002065 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002066 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002067 INIT_LIST_HEAD(&wdata->list);
2068 init_completion(&wdata->done);
2069 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070 }
2071 return wdata;
2072}
2073
2074/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002075 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076 * workqueue completion task.
2077 */
2078static void
2079cifs_writev_callback(struct mid_q_entry *mid)
2080{
2081 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002082 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002083 unsigned int written;
2084 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2085
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002086 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002087 case MID_RESPONSE_RECEIVED:
2088 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2089 if (wdata->result != 0)
2090 break;
2091
2092 written = le16_to_cpu(smb->CountHigh);
2093 written <<= 16;
2094 written += le16_to_cpu(smb->Count);
2095 /*
2096 * Mask off high 16 bits when bytes written as returned
2097 * by the server is greater than bytes requested by the
2098 * client. OS/2 servers are known to set incorrect
2099 * CountHigh values.
2100 */
2101 if (written > wdata->bytes)
2102 written &= 0xFFFF;
2103
2104 if (written < wdata->bytes)
2105 wdata->result = -ENOSPC;
2106 else
2107 wdata->bytes = written;
2108 break;
2109 case MID_REQUEST_SUBMITTED:
2110 case MID_RETRY_NEEDED:
2111 wdata->result = -EAGAIN;
2112 break;
2113 default:
2114 wdata->result = -EIO;
2115 break;
2116 }
2117
Jeff Laytonda472fc2012-03-23 14:40:53 -04002118 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002119 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002120 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002121}
2122
2123/* cifs_async_writev - send an async write, and set up mid to handle result */
2124int
Steve French4a5c80d2014-02-07 20:45:12 -06002125cifs_async_writev(struct cifs_writedata *wdata,
2126 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002127{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002128 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002129 WRITE_REQ *smb = NULL;
2130 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002131 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002132 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002133 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002134
2135 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2136 wct = 14;
2137 } else {
2138 wct = 12;
2139 if (wdata->offset >> 32 > 0) {
2140 /* can not handle big offset for old srv */
2141 return -EIO;
2142 }
2143 }
2144
2145 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2146 if (rc)
2147 goto async_writev_out;
2148
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002149 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2150 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002151
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002152 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002153 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002154 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2155 if (wct == 14)
2156 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2157 smb->Reserved = 0xFFFFFFFF;
2158 smb->WriteMode = 0;
2159 smb->Remaining = 0;
2160
2161 smb->DataOffset =
2162 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2163
2164 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002165 iov[0].iov_len = 4;
2166 iov[0].iov_base = smb;
2167 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2168 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002170 rqst.rq_iov = iov;
2171 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002172 rqst.rq_pages = wdata->pages;
2173 rqst.rq_npages = wdata->nr_pages;
2174 rqst.rq_pagesz = wdata->pagesz;
2175 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002176
Joe Perchesf96637b2013-05-04 22:12:25 -05002177 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2178 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002179
2180 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2181 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2182
2183 if (wct == 14) {
2184 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2185 put_bcc(wdata->bytes + 1, &smb->hdr);
2186 } else {
2187 /* wct == 12 */
2188 struct smb_com_writex_req *smbw =
2189 (struct smb_com_writex_req *)smb;
2190 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2191 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002192 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002193 }
2194
2195 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002196 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002197 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002198
2199 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002200 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002201 else
Steve French4a5c80d2014-02-07 20:45:12 -06002202 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002203
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002204async_writev_out:
2205 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002206 return rc;
2207}
2208
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002209int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002210CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002211 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212{
2213 int rc = -EACCES;
2214 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002215 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002216 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002217 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002218 __u32 pid = io_parms->pid;
2219 __u16 netfid = io_parms->netfid;
2220 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002221 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002222 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002223 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002225 *nbytes = 0;
2226
Joe Perchesf96637b2013-05-04 22:12:25 -05002227 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002228
Steve French4c3130e2008-12-09 00:28:16 +00002229 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002230 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002231 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002232 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002233 if ((offset >> 32) > 0) {
2234 /* can not handle big offset for old srv */
2235 return -EIO;
2236 }
2237 }
Steve French8cc64c62005-10-03 13:49:43 -07002238 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 if (rc)
2240 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002241
2242 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2243 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2244
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 /* tcon and ses pointer are checked in smb_init */
2246 if (tcon->ses->server == NULL)
2247 return -ECONNABORTED;
2248
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002249 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 pSMB->Fid = netfid;
2251 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002252 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002253 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 pSMB->Reserved = 0xFFFFFFFF;
2255 pSMB->WriteMode = 0;
2256 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002257
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002259 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
Steve French3e844692005-10-03 13:37:24 -07002261 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2262 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002263 /* header + 1 byte pad */
2264 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002265 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002266 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002267 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002268 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002269 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002270 pSMB->ByteCount = cpu_to_le16(count + 1);
2271 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002272 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002273 (struct smb_com_writex_req *)pSMB;
2274 pSMBW->ByteCount = cpu_to_le16(count + 5);
2275 }
Steve French3e844692005-10-03 13:37:24 -07002276 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002277 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002278 iov[0].iov_len = smb_hdr_len + 4;
2279 else /* wct == 12 pad bigger by four bytes */
2280 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002281
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002282 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2283 &rsp_iov);
2284 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002285 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002287 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002288 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002289 /* presumably this can not happen, but best to be safe */
2290 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002291 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002292 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002293 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2294 *nbytes = (*nbytes) << 16;
2295 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302296
2297 /*
2298 * Mask off high 16 bits when bytes written as returned by the
2299 * server is greater than bytes requested by the client. OS/2
2300 * servers are known to set incorrect CountHigh values.
2301 */
2302 if (*nbytes > count)
2303 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002306 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Steve French50c2f752007-07-13 00:33:32 +00002308 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 since file handle passed in no longer valid */
2310
2311 return rc;
2312}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002313
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002314int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2315 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002316 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2317{
2318 int rc = 0;
2319 LOCK_REQ *pSMB = NULL;
2320 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002321 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002322 int resp_buf_type;
2323 __u16 count;
2324
Joe Perchesf96637b2013-05-04 22:12:25 -05002325 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2326 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002327
2328 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2329 if (rc)
2330 return rc;
2331
2332 pSMB->Timeout = 0;
2333 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2334 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2335 pSMB->LockType = lock_type;
2336 pSMB->AndXCommand = 0xFF; /* none */
2337 pSMB->Fid = netfid; /* netfid stays le */
2338
2339 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2340 inc_rfc1001_len(pSMB, count);
2341 pSMB->ByteCount = cpu_to_le16(count);
2342
2343 iov[0].iov_base = (char *)pSMB;
2344 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2345 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2346 iov[1].iov_base = (char *)buf;
2347 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2348
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002349 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002350 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2351 &rsp_iov);
2352 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002353 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002354 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002355
2356 return rc;
2357}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002358
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002360CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002361 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002363 const __u32 numLock, const __u8 lockType,
2364 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365{
2366 int rc = 0;
2367 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002368/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002370 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 __u16 count;
2372
Joe Perchesf96637b2013-05-04 22:12:25 -05002373 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2374 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002375 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if (rc)
2378 return rc;
2379
Steve French790fe572007-07-07 19:25:05 +00002380 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002381 /* no response expected */
2382 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002384 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002385 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2387 } else {
2388 pSMB->Timeout = 0;
2389 }
2390
2391 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2392 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2393 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002394 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 pSMB->AndXCommand = 0xFF; /* none */
2396 pSMB->Fid = smb_file_id; /* netfid stays le */
2397
Steve French790fe572007-07-07 19:25:05 +00002398 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002399 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 /* BB where to store pid high? */
2401 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2402 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2403 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2404 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2405 count = sizeof(LOCKING_ANDX_RANGE);
2406 } else {
2407 /* oplock break */
2408 count = 0;
2409 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002410 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 pSMB->ByteCount = cpu_to_le16(count);
2412
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002413 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002414 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002415 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002416 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002417 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002418 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002419 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002420 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002421 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
Steve French50c2f752007-07-13 00:33:32 +00002423 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 since file handle passed in no longer valid */
2425 return rc;
2426}
2427
2428int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002429CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002430 const __u16 smb_file_id, const __u32 netpid,
2431 const loff_t start_offset, const __u64 len,
2432 struct file_lock *pLockData, const __u16 lock_type,
2433 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002434{
2435 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2436 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002437 struct cifs_posix_lock *parm_data;
2438 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002439 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002440 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002441 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002442 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002443 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002444 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002445
Joe Perchesf96637b2013-05-04 22:12:25 -05002446 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002447
Steve French08547b02006-02-28 22:39:25 +00002448 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2449
2450 if (rc)
2451 return rc;
2452
2453 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2454
Steve French50c2f752007-07-13 00:33:32 +00002455 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002456 pSMB->MaxSetupCount = 0;
2457 pSMB->Reserved = 0;
2458 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002459 pSMB->Reserved2 = 0;
2460 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2461 offset = param_offset + params;
2462
Steve French08547b02006-02-28 22:39:25 +00002463 count = sizeof(struct cifs_posix_lock);
2464 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002465 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002466 pSMB->SetupCount = 1;
2467 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002468 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002469 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2470 else
2471 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2472 byte_count = 3 /* pad */ + params + count;
2473 pSMB->DataCount = cpu_to_le16(count);
2474 pSMB->ParameterCount = cpu_to_le16(params);
2475 pSMB->TotalDataCount = pSMB->DataCount;
2476 pSMB->TotalParameterCount = pSMB->ParameterCount;
2477 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002478 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002479 (((char *) &pSMB->hdr.Protocol) + offset);
2480
2481 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002482 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002483 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002484 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002485 pSMB->Timeout = cpu_to_le32(-1);
2486 } else
2487 pSMB->Timeout = 0;
2488
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002489 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002490 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002491 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002492
2493 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002494 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002495 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2496 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002497 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002498 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002499 if (waitFlag) {
2500 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2501 (struct smb_hdr *) pSMBr, &bytes_returned);
2502 } else {
Steve French133672e2007-11-13 22:41:37 +00002503 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002504 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002505 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002506 &resp_buf_type, timeout, &rsp_iov);
2507 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002508 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002509 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002510
Steve French08547b02006-02-28 22:39:25 +00002511 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002512 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002513 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002514 /* lock structure can be returned on get */
2515 __u16 data_offset;
2516 __u16 data_count;
2517 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002518
Jeff Layton820a8032011-05-04 08:05:26 -04002519 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002520 rc = -EIO; /* bad smb */
2521 goto plk_err_exit;
2522 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002523 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2524 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002525 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002526 rc = -EIO;
2527 goto plk_err_exit;
2528 }
2529 parm_data = (struct cifs_posix_lock *)
2530 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002531 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002532 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002533 else {
2534 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002535 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002536 pLockData->fl_type = F_RDLCK;
2537 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002538 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002539 pLockData->fl_type = F_WRLCK;
2540
Steve French5443d132011-03-13 05:08:25 +00002541 pLockData->fl_start = le64_to_cpu(parm_data->start);
2542 pLockData->fl_end = pLockData->fl_start +
2543 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002544 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002545 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002546 }
Steve French50c2f752007-07-13 00:33:32 +00002547
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002548plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002549 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002550
Steve French08547b02006-02-28 22:39:25 +00002551 /* Note: On -EAGAIN error only caller can retry on handle based calls
2552 since file handle passed in no longer valid */
2553
2554 return rc;
2555}
2556
2557
2558int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002559CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560{
2561 int rc = 0;
2562 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002563 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
2565/* do not retry on dead session on close */
2566 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002567 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 return 0;
2569 if (rc)
2570 return rc;
2571
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002573 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002575 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002576 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002577 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002579 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002581 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 }
2583 }
2584
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002586 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 rc = 0;
2588
2589 return rc;
2590}
2591
2592int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002593CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002594{
2595 int rc = 0;
2596 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002597 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002598
2599 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2600 if (rc)
2601 return rc;
2602
2603 pSMB->FileID = (__u16) smb_file_id;
2604 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002605 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002606 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002607 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002608 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002609 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002610
2611 return rc;
2612}
2613
2614int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002615CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002616 const char *from_name, const char *to_name,
2617 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618{
2619 int rc = 0;
2620 RENAME_REQ *pSMB = NULL;
2621 RENAME_RSP *pSMBr = NULL;
2622 int bytes_returned;
2623 int name_len, name_len2;
2624 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002625 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
Joe Perchesf96637b2013-05-04 22:12:25 -05002627 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628renameRetry:
2629 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2630 (void **) &pSMBr);
2631 if (rc)
2632 return rc;
2633
2634 pSMB->BufferFormat = 0x04;
2635 pSMB->SearchAttributes =
2636 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2637 ATTR_DIRECTORY);
2638
2639 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002640 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2641 from_name, PATH_MAX,
2642 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 name_len++; /* trailing null */
2644 name_len *= 2;
2645 pSMB->OldFileName[name_len] = 0x04; /* pad */
2646 /* protocol requires ASCII signature byte on Unicode string */
2647 pSMB->OldFileName[name_len + 1] = 0x00;
2648 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002649 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002650 to_name, PATH_MAX, cifs_sb->local_nls,
2651 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2653 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002654 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002655 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002657 strncpy(pSMB->OldFileName, from_name, name_len);
2658 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 name_len2++; /* trailing null */
2660 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002661 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 name_len2++; /* trailing null */
2663 name_len2++; /* signature byte */
2664 }
2665
2666 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002667 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 pSMB->ByteCount = cpu_to_le16(count);
2669
2670 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2671 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002672 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002673 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002674 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 cifs_buf_release(pSMB);
2677
2678 if (rc == -EAGAIN)
2679 goto renameRetry;
2680
2681 return rc;
2682}
2683
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002684int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002685 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002686 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687{
2688 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2689 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002690 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 char *data_offset;
2692 char dummy_string[30];
2693 int rc = 0;
2694 int bytes_returned = 0;
2695 int len_of_str;
2696 __u16 params, param_offset, offset, count, byte_count;
2697
Joe Perchesf96637b2013-05-04 22:12:25 -05002698 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2700 (void **) &pSMBr);
2701 if (rc)
2702 return rc;
2703
2704 params = 6;
2705 pSMB->MaxSetupCount = 0;
2706 pSMB->Reserved = 0;
2707 pSMB->Flags = 0;
2708 pSMB->Timeout = 0;
2709 pSMB->Reserved2 = 0;
2710 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2711 offset = param_offset + params;
2712
2713 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2714 rename_info = (struct set_file_rename *) data_offset;
2715 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002716 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 pSMB->SetupCount = 1;
2718 pSMB->Reserved3 = 0;
2719 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2720 byte_count = 3 /* pad */ + params;
2721 pSMB->ParameterCount = cpu_to_le16(params);
2722 pSMB->TotalParameterCount = pSMB->ParameterCount;
2723 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2724 pSMB->DataOffset = cpu_to_le16(offset);
2725 /* construct random name ".cifs_tmp<inodenum><mid>" */
2726 rename_info->overwrite = cpu_to_le32(1);
2727 rename_info->root_fid = 0;
2728 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002729 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002730 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002731 len_of_str =
2732 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002733 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002735 len_of_str =
2736 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002737 target_name, PATH_MAX, nls_codepage,
2738 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 }
2740 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002741 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 byte_count += count;
2743 pSMB->DataCount = cpu_to_le16(count);
2744 pSMB->TotalDataCount = pSMB->DataCount;
2745 pSMB->Fid = netfid;
2746 pSMB->InformationLevel =
2747 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2748 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002749 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 pSMB->ByteCount = cpu_to_le16(byte_count);
2751 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002752 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002753 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002754 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002755 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2756 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002757
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 cifs_buf_release(pSMB);
2759
2760 /* Note: On -EAGAIN error only caller can retry on handle based calls
2761 since file handle passed in no longer valid */
2762
2763 return rc;
2764}
2765
2766int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002767CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2768 const char *fromName, const __u16 target_tid, const char *toName,
2769 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770{
2771 int rc = 0;
2772 COPY_REQ *pSMB = NULL;
2773 COPY_RSP *pSMBr = NULL;
2774 int bytes_returned;
2775 int name_len, name_len2;
2776 __u16 count;
2777
Joe Perchesf96637b2013-05-04 22:12:25 -05002778 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779copyRetry:
2780 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2781 (void **) &pSMBr);
2782 if (rc)
2783 return rc;
2784
2785 pSMB->BufferFormat = 0x04;
2786 pSMB->Tid2 = target_tid;
2787
2788 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2789
2790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002791 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2792 fromName, PATH_MAX, nls_codepage,
2793 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 name_len++; /* trailing null */
2795 name_len *= 2;
2796 pSMB->OldFileName[name_len] = 0x04; /* pad */
2797 /* protocol requires ASCII signature byte on Unicode string */
2798 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002799 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002800 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2801 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2803 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002804 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 name_len = strnlen(fromName, PATH_MAX);
2806 name_len++; /* trailing null */
2807 strncpy(pSMB->OldFileName, fromName, name_len);
2808 name_len2 = strnlen(toName, PATH_MAX);
2809 name_len2++; /* trailing null */
2810 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2811 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2812 name_len2++; /* trailing null */
2813 name_len2++; /* signature byte */
2814 }
2815
2816 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002817 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 pSMB->ByteCount = cpu_to_le16(count);
2819
2820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2822 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002823 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2824 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 }
Steve French0d817bc2008-05-22 02:02:03 +00002826 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827
2828 if (rc == -EAGAIN)
2829 goto copyRetry;
2830
2831 return rc;
2832}
2833
2834int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002835CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002837 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838{
2839 TRANSACTION2_SPI_REQ *pSMB = NULL;
2840 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2841 char *data_offset;
2842 int name_len;
2843 int name_len_target;
2844 int rc = 0;
2845 int bytes_returned = 0;
2846 __u16 params, param_offset, offset, byte_count;
2847
Joe Perchesf96637b2013-05-04 22:12:25 -05002848 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849createSymLinkRetry:
2850 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2851 (void **) &pSMBr);
2852 if (rc)
2853 return rc;
2854
2855 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2856 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002857 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2858 /* find define for this maxpathcomponent */
2859 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 name_len++; /* trailing null */
2861 name_len *= 2;
2862
Steve French50c2f752007-07-13 00:33:32 +00002863 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 name_len = strnlen(fromName, PATH_MAX);
2865 name_len++; /* trailing null */
2866 strncpy(pSMB->FileName, fromName, name_len);
2867 }
2868 params = 6 + name_len;
2869 pSMB->MaxSetupCount = 0;
2870 pSMB->Reserved = 0;
2871 pSMB->Flags = 0;
2872 pSMB->Timeout = 0;
2873 pSMB->Reserved2 = 0;
2874 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002875 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 offset = param_offset + params;
2877
2878 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2880 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002881 cifsConvertToUTF16((__le16 *) data_offset, toName,
2882 /* find define for this maxpathcomponent */
2883 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 name_len_target++; /* trailing null */
2885 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002886 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 name_len_target = strnlen(toName, PATH_MAX);
2888 name_len_target++; /* trailing null */
2889 strncpy(data_offset, toName, name_len_target);
2890 }
2891
2892 pSMB->MaxParameterCount = cpu_to_le16(2);
2893 /* BB find exact max on data count below from sess */
2894 pSMB->MaxDataCount = cpu_to_le16(1000);
2895 pSMB->SetupCount = 1;
2896 pSMB->Reserved3 = 0;
2897 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2898 byte_count = 3 /* pad */ + params + name_len_target;
2899 pSMB->DataCount = cpu_to_le16(name_len_target);
2900 pSMB->ParameterCount = cpu_to_le16(params);
2901 pSMB->TotalDataCount = pSMB->DataCount;
2902 pSMB->TotalParameterCount = pSMB->ParameterCount;
2903 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2904 pSMB->DataOffset = cpu_to_le16(offset);
2905 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2906 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002907 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 pSMB->ByteCount = cpu_to_le16(byte_count);
2909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002911 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002912 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002913 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2914 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
Steve French0d817bc2008-05-22 02:02:03 +00002916 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
2918 if (rc == -EAGAIN)
2919 goto createSymLinkRetry;
2920
2921 return rc;
2922}
2923
2924int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002925CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002927 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928{
2929 TRANSACTION2_SPI_REQ *pSMB = NULL;
2930 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2931 char *data_offset;
2932 int name_len;
2933 int name_len_target;
2934 int rc = 0;
2935 int bytes_returned = 0;
2936 __u16 params, param_offset, offset, byte_count;
2937
Joe Perchesf96637b2013-05-04 22:12:25 -05002938 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939createHardLinkRetry:
2940 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2941 (void **) &pSMBr);
2942 if (rc)
2943 return rc;
2944
2945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002946 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2947 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 name_len++; /* trailing null */
2949 name_len *= 2;
2950
Steve French50c2f752007-07-13 00:33:32 +00002951 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 name_len = strnlen(toName, PATH_MAX);
2953 name_len++; /* trailing null */
2954 strncpy(pSMB->FileName, toName, name_len);
2955 }
2956 params = 6 + name_len;
2957 pSMB->MaxSetupCount = 0;
2958 pSMB->Reserved = 0;
2959 pSMB->Flags = 0;
2960 pSMB->Timeout = 0;
2961 pSMB->Reserved2 = 0;
2962 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002963 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 offset = param_offset + params;
2965
2966 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2968 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002969 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2970 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 name_len_target++; /* trailing null */
2972 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002973 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 name_len_target = strnlen(fromName, PATH_MAX);
2975 name_len_target++; /* trailing null */
2976 strncpy(data_offset, fromName, name_len_target);
2977 }
2978
2979 pSMB->MaxParameterCount = cpu_to_le16(2);
2980 /* BB find exact max on data count below from sess*/
2981 pSMB->MaxDataCount = cpu_to_le16(1000);
2982 pSMB->SetupCount = 1;
2983 pSMB->Reserved3 = 0;
2984 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2985 byte_count = 3 /* pad */ + params + name_len_target;
2986 pSMB->ParameterCount = cpu_to_le16(params);
2987 pSMB->TotalParameterCount = pSMB->ParameterCount;
2988 pSMB->DataCount = cpu_to_le16(name_len_target);
2989 pSMB->TotalDataCount = pSMB->DataCount;
2990 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2991 pSMB->DataOffset = cpu_to_le16(offset);
2992 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2993 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002994 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 pSMB->ByteCount = cpu_to_le16(byte_count);
2996 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2997 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002998 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002999 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003000 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3001 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
3003 cifs_buf_release(pSMB);
3004 if (rc == -EAGAIN)
3005 goto createHardLinkRetry;
3006
3007 return rc;
3008}
3009
3010int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003011CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003012 const char *from_name, const char *to_name,
3013 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014{
3015 int rc = 0;
3016 NT_RENAME_REQ *pSMB = NULL;
3017 RENAME_RSP *pSMBr = NULL;
3018 int bytes_returned;
3019 int name_len, name_len2;
3020 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003021 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022
Joe Perchesf96637b2013-05-04 22:12:25 -05003023 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024winCreateHardLinkRetry:
3025
3026 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3027 (void **) &pSMBr);
3028 if (rc)
3029 return rc;
3030
3031 pSMB->SearchAttributes =
3032 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3033 ATTR_DIRECTORY);
3034 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3035 pSMB->ClusterCount = 0;
3036
3037 pSMB->BufferFormat = 0x04;
3038
3039 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3040 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003041 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3042 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 name_len++; /* trailing null */
3044 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003045
3046 /* protocol specifies ASCII buffer format (0x04) for unicode */
3047 pSMB->OldFileName[name_len] = 0x04;
3048 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003050 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003051 to_name, PATH_MAX, cifs_sb->local_nls,
3052 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3054 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003055 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003056 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003058 strncpy(pSMB->OldFileName, from_name, name_len);
3059 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 name_len2++; /* trailing null */
3061 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003062 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 name_len2++; /* trailing null */
3064 name_len2++; /* signature byte */
3065 }
3066
3067 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003068 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 pSMB->ByteCount = cpu_to_le16(count);
3070
3071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003073 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003074 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003075 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003076
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 cifs_buf_release(pSMB);
3078 if (rc == -EAGAIN)
3079 goto winCreateHardLinkRetry;
3080
3081 return rc;
3082}
3083
3084int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003085CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003086 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003087 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088{
3089/* SMB_QUERY_FILE_UNIX_LINK */
3090 TRANSACTION2_QPI_REQ *pSMB = NULL;
3091 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3092 int rc = 0;
3093 int bytes_returned;
3094 int name_len;
3095 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003096 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
Joe Perchesf96637b2013-05-04 22:12:25 -05003098 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
3100querySymLinkRetry:
3101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3102 (void **) &pSMBr);
3103 if (rc)
3104 return rc;
3105
3106 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3107 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003108 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3109 searchName, PATH_MAX, nls_codepage,
3110 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 name_len++; /* trailing null */
3112 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003113 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 name_len = strnlen(searchName, PATH_MAX);
3115 name_len++; /* trailing null */
3116 strncpy(pSMB->FileName, searchName, name_len);
3117 }
3118
3119 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3120 pSMB->TotalDataCount = 0;
3121 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003122 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 pSMB->MaxSetupCount = 0;
3124 pSMB->Reserved = 0;
3125 pSMB->Flags = 0;
3126 pSMB->Timeout = 0;
3127 pSMB->Reserved2 = 0;
3128 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003129 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 pSMB->DataCount = 0;
3131 pSMB->DataOffset = 0;
3132 pSMB->SetupCount = 1;
3133 pSMB->Reserved3 = 0;
3134 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3135 byte_count = params + 1 /* pad */ ;
3136 pSMB->TotalParameterCount = cpu_to_le16(params);
3137 pSMB->ParameterCount = pSMB->TotalParameterCount;
3138 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3139 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003140 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 pSMB->ByteCount = cpu_to_le16(byte_count);
3142
3143 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3144 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3145 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003146 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 } else {
3148 /* decode response */
3149
3150 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003152 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003153 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003155 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003156 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157
Jeff Layton460b9692009-04-30 07:17:56 -04003158 data_start = ((char *) &pSMBr->hdr.Protocol) +
3159 le16_to_cpu(pSMBr->t2.DataOffset);
3160
Steve French0e0d2cf2009-05-01 05:27:32 +00003161 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3162 is_unicode = true;
3163 else
3164 is_unicode = false;
3165
Steve French737b7582005-04-28 22:41:06 -07003166 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003167 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3168 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003169 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003170 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 }
3172 }
3173 cifs_buf_release(pSMB);
3174 if (rc == -EAGAIN)
3175 goto querySymLinkRetry;
3176 return rc;
3177}
3178
Steve Frenchc52a95542011-02-24 06:16:22 +00003179/*
3180 * Recent Windows versions now create symlinks more frequently
3181 * and they use the "reparse point" mechanism below. We can of course
3182 * do symlinks nicely to Samba and other servers which support the
3183 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3184 * "MF" symlinks optionally, but for recent Windows we really need to
3185 * reenable the code below and fix the cifs_symlink callers to handle this.
3186 * In the interim this code has been moved to its own config option so
3187 * it is not compiled in by default until callers fixed up and more tested.
3188 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003190CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3191 __u16 fid, char **symlinkinfo,
3192 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193{
3194 int rc = 0;
3195 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003196 struct smb_com_transaction_ioctl_req *pSMB;
3197 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003198 bool is_unicode;
3199 unsigned int sub_len;
3200 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003201 struct reparse_symlink_data *reparse_buf;
3202 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003203 __u32 data_offset, data_count;
3204 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003206 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3208 (void **) &pSMBr);
3209 if (rc)
3210 return rc;
3211
3212 pSMB->TotalParameterCount = 0 ;
3213 pSMB->TotalDataCount = 0;
3214 pSMB->MaxParameterCount = cpu_to_le32(2);
3215 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003216 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 pSMB->MaxSetupCount = 4;
3218 pSMB->Reserved = 0;
3219 pSMB->ParameterOffset = 0;
3220 pSMB->DataCount = 0;
3221 pSMB->DataOffset = 0;
3222 pSMB->SetupCount = 4;
3223 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3224 pSMB->ParameterCount = pSMB->TotalParameterCount;
3225 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3226 pSMB->IsFsctl = 1; /* FSCTL */
3227 pSMB->IsRootFlag = 0;
3228 pSMB->Fid = fid; /* file handle always le */
3229 pSMB->ByteCount = 0;
3230
3231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3233 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003234 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003235 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 }
Steve French989c7e52009-05-02 05:32:20 +00003237
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003238 data_offset = le32_to_cpu(pSMBr->DataOffset);
3239 data_count = le32_to_cpu(pSMBr->DataCount);
3240 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3241 /* BB also check enough total bytes returned */
3242 rc = -EIO; /* bad smb */
3243 goto qreparse_out;
3244 }
3245 if (!data_count || (data_count > 2048)) {
3246 rc = -EIO;
3247 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3248 goto qreparse_out;
3249 }
3250 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003251 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003252 ((char *)&pSMBr->hdr.Protocol + data_offset);
3253 if ((char *)reparse_buf >= end_of_smb) {
3254 rc = -EIO;
3255 goto qreparse_out;
3256 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003257 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3258 cifs_dbg(FYI, "NFS style reparse tag\n");
3259 posix_buf = (struct reparse_posix_data *)reparse_buf;
3260
3261 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3262 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3263 le64_to_cpu(posix_buf->InodeType));
3264 rc = -EOPNOTSUPP;
3265 goto qreparse_out;
3266 }
3267 is_unicode = true;
3268 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3269 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3270 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3271 rc = -EIO;
3272 goto qreparse_out;
3273 }
3274 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3275 sub_len, is_unicode, nls_codepage);
3276 goto qreparse_out;
3277 } else if (reparse_buf->ReparseTag !=
3278 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3279 rc = -EOPNOTSUPP;
3280 goto qreparse_out;
3281 }
3282
3283 /* Reparse tag is NTFS symlink */
3284 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3285 reparse_buf->PathBuffer;
3286 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3287 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003288 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3289 rc = -EIO;
3290 goto qreparse_out;
3291 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003292 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3293 is_unicode = true;
3294 else
3295 is_unicode = false;
3296
3297 /* BB FIXME investigate remapping reserved chars here */
3298 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3299 nls_codepage);
3300 if (!*symlinkinfo)
3301 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003303 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003305 /*
3306 * Note: On -EAGAIN error only caller can retry on handle based calls
3307 * since file handle passed in no longer valid.
3308 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 return rc;
3310}
3311
Steve Frenchc7f508a2013-10-14 15:27:32 -05003312int
3313CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3314 __u16 fid)
3315{
3316 int rc = 0;
3317 int bytes_returned;
3318 struct smb_com_transaction_compr_ioctl_req *pSMB;
3319 struct smb_com_transaction_ioctl_rsp *pSMBr;
3320
3321 cifs_dbg(FYI, "Set compression for %u\n", fid);
3322 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3323 (void **) &pSMBr);
3324 if (rc)
3325 return rc;
3326
3327 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3328
3329 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003330 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003331 pSMB->MaxParameterCount = 0;
3332 pSMB->MaxDataCount = 0;
3333 pSMB->MaxSetupCount = 4;
3334 pSMB->Reserved = 0;
3335 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003336 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003337 pSMB->DataOffset =
3338 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3339 compression_state) - 4); /* 84 */
3340 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003341 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003342 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003343 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003344 pSMB->IsFsctl = 1; /* FSCTL */
3345 pSMB->IsRootFlag = 0;
3346 pSMB->Fid = fid; /* file handle always le */
3347 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003348 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003349 inc_rfc1001_len(pSMB, 5);
3350
3351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3352 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3353 if (rc)
3354 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3355
3356 cifs_buf_release(pSMB);
3357
3358 /*
3359 * Note: On -EAGAIN error only caller can retry on handle based calls
3360 * since file handle passed in no longer valid.
3361 */
3362 return rc;
3363}
3364
3365
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366#ifdef CONFIG_CIFS_POSIX
3367
3368/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003369static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003370 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371{
3372 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003373 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3374 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3375 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003376/*
3377 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3378 ace->e_perm, ace->e_tag, ace->e_id);
3379*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380
3381 return;
3382}
3383
3384/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003385static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3386 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387{
3388 int size = 0;
3389 int i;
3390 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003391 struct cifs_posix_ace *pACE;
3392 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003393 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
3395 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3396 return -EOPNOTSUPP;
3397
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003398 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 count = le16_to_cpu(cifs_acl->access_entry_count);
3400 pACE = &cifs_acl->ace_array[0];
3401 size = sizeof(struct cifs_posix_acl);
3402 size += sizeof(struct cifs_posix_ace) * count;
3403 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003404 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003405 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3406 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 return -EINVAL;
3408 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003409 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 count = le16_to_cpu(cifs_acl->access_entry_count);
3411 size = sizeof(struct cifs_posix_acl);
3412 size += sizeof(struct cifs_posix_ace) * count;
3413/* skip past access ACEs to get to default ACEs */
3414 pACE = &cifs_acl->ace_array[count];
3415 count = le16_to_cpu(cifs_acl->default_entry_count);
3416 size += sizeof(struct cifs_posix_ace) * count;
3417 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003418 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 return -EINVAL;
3420 } else {
3421 /* illegal type */
3422 return -EINVAL;
3423 }
3424
3425 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003426 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003427 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003428 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 return -ERANGE;
3430 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003431 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3432
Steve Frenchff7feac2005-11-15 16:45:16 -08003433 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003434 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003435 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003436 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 }
3438 }
3439 return size;
3440}
3441
Steve French50c2f752007-07-13 00:33:32 +00003442static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003443 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444{
3445 __u16 rc = 0; /* 0 = ACL converted ok */
3446
Steve Frenchff7feac2005-11-15 16:45:16 -08003447 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3448 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003450 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 /* Probably no need to le convert -1 on any arch but can not hurt */
3452 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003453 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003454 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003455/*
3456 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3457 ace->e_perm, ace->e_tag, ace->e_id);
3458*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 return rc;
3460}
3461
3462/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003463static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3464 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465{
3466 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003467 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003468 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003469 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 int count;
3471 int i;
3472
Steve French790fe572007-07-07 19:25:05 +00003473 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 return 0;
3475
3476 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003477 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3478 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003479 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003480 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3481 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 return 0;
3483 }
3484 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003485 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003486 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003487 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003488 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003489 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003490 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003491 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003492 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 return 0;
3494 }
Steve French50c2f752007-07-13 00:33:32 +00003495 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003496 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003497 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 /* ACE not converted */
3499 break;
3500 }
3501 }
Steve French790fe572007-07-07 19:25:05 +00003502 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3504 rc += sizeof(struct cifs_posix_acl);
3505 /* BB add check to make sure ACL does not overflow SMB */
3506 }
3507 return rc;
3508}
3509
3510int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003511CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003512 const unsigned char *searchName,
3513 char *acl_inf, const int buflen, const int acl_type,
3514 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515{
3516/* SMB_QUERY_POSIX_ACL */
3517 TRANSACTION2_QPI_REQ *pSMB = NULL;
3518 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3519 int rc = 0;
3520 int bytes_returned;
3521 int name_len;
3522 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003523
Joe Perchesf96637b2013-05-04 22:12:25 -05003524 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
3526queryAclRetry:
3527 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3528 (void **) &pSMBr);
3529 if (rc)
3530 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003531
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3533 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003534 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3535 searchName, PATH_MAX, nls_codepage,
3536 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 name_len++; /* trailing null */
3538 name_len *= 2;
3539 pSMB->FileName[name_len] = 0;
3540 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003541 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 name_len = strnlen(searchName, PATH_MAX);
3543 name_len++; /* trailing null */
3544 strncpy(pSMB->FileName, searchName, name_len);
3545 }
3546
3547 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3548 pSMB->TotalDataCount = 0;
3549 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003550 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 pSMB->MaxDataCount = cpu_to_le16(4000);
3552 pSMB->MaxSetupCount = 0;
3553 pSMB->Reserved = 0;
3554 pSMB->Flags = 0;
3555 pSMB->Timeout = 0;
3556 pSMB->Reserved2 = 0;
3557 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003558 offsetof(struct smb_com_transaction2_qpi_req,
3559 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 pSMB->DataCount = 0;
3561 pSMB->DataOffset = 0;
3562 pSMB->SetupCount = 1;
3563 pSMB->Reserved3 = 0;
3564 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3565 byte_count = params + 1 /* pad */ ;
3566 pSMB->TotalParameterCount = cpu_to_le16(params);
3567 pSMB->ParameterCount = pSMB->TotalParameterCount;
3568 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3569 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003570 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 pSMB->ByteCount = cpu_to_le16(byte_count);
3572
3573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003575 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003577 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 } else {
3579 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003580
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003583 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 rc = -EIO; /* bad smb */
3585 else {
3586 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3587 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3588 rc = cifs_copy_posix_acl(acl_inf,
3589 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003590 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 }
3592 }
3593 cifs_buf_release(pSMB);
3594 if (rc == -EAGAIN)
3595 goto queryAclRetry;
3596 return rc;
3597}
3598
3599int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003600CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003601 const unsigned char *fileName,
3602 const char *local_acl, const int buflen,
3603 const int acl_type,
3604 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605{
3606 struct smb_com_transaction2_spi_req *pSMB = NULL;
3607 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3608 char *parm_data;
3609 int name_len;
3610 int rc = 0;
3611 int bytes_returned = 0;
3612 __u16 params, byte_count, data_count, param_offset, offset;
3613
Joe Perchesf96637b2013-05-04 22:12:25 -05003614 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615setAclRetry:
3616 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003617 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 if (rc)
3619 return rc;
3620 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3621 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003622 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3623 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 name_len++; /* trailing null */
3625 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003626 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 name_len = strnlen(fileName, PATH_MAX);
3628 name_len++; /* trailing null */
3629 strncpy(pSMB->FileName, fileName, name_len);
3630 }
3631 params = 6 + name_len;
3632 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003633 /* BB find max SMB size from sess */
3634 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 pSMB->MaxSetupCount = 0;
3636 pSMB->Reserved = 0;
3637 pSMB->Flags = 0;
3638 pSMB->Timeout = 0;
3639 pSMB->Reserved2 = 0;
3640 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003641 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 offset = param_offset + params;
3643 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3644 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3645
3646 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003647 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648
Steve French790fe572007-07-07 19:25:05 +00003649 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 rc = -EOPNOTSUPP;
3651 goto setACLerrorExit;
3652 }
3653 pSMB->DataOffset = cpu_to_le16(offset);
3654 pSMB->SetupCount = 1;
3655 pSMB->Reserved3 = 0;
3656 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3657 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3658 byte_count = 3 /* pad */ + params + data_count;
3659 pSMB->DataCount = cpu_to_le16(data_count);
3660 pSMB->TotalDataCount = pSMB->DataCount;
3661 pSMB->ParameterCount = cpu_to_le16(params);
3662 pSMB->TotalParameterCount = pSMB->ParameterCount;
3663 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003664 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 pSMB->ByteCount = cpu_to_le16(byte_count);
3666 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003667 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003668 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003669 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670
3671setACLerrorExit:
3672 cifs_buf_release(pSMB);
3673 if (rc == -EAGAIN)
3674 goto setAclRetry;
3675 return rc;
3676}
3677
Steve Frenchf654bac2005-04-28 22:41:04 -07003678/* BB fix tabs in this function FIXME BB */
3679int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003680CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003681 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003682{
Steve French50c2f752007-07-13 00:33:32 +00003683 int rc = 0;
3684 struct smb_t2_qfi_req *pSMB = NULL;
3685 struct smb_t2_qfi_rsp *pSMBr = NULL;
3686 int bytes_returned;
3687 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003688
Joe Perchesf96637b2013-05-04 22:12:25 -05003689 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003690 if (tcon == NULL)
3691 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003692
3693GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003694 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3695 (void **) &pSMBr);
3696 if (rc)
3697 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003698
Steve Frenchad7a2922008-02-07 23:25:02 +00003699 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003700 pSMB->t2.TotalDataCount = 0;
3701 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3702 /* BB find exact max data count below from sess structure BB */
3703 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3704 pSMB->t2.MaxSetupCount = 0;
3705 pSMB->t2.Reserved = 0;
3706 pSMB->t2.Flags = 0;
3707 pSMB->t2.Timeout = 0;
3708 pSMB->t2.Reserved2 = 0;
3709 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3710 Fid) - 4);
3711 pSMB->t2.DataCount = 0;
3712 pSMB->t2.DataOffset = 0;
3713 pSMB->t2.SetupCount = 1;
3714 pSMB->t2.Reserved3 = 0;
3715 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3716 byte_count = params + 1 /* pad */ ;
3717 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3718 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3719 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3720 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003721 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003722 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003723 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003724
Steve French790fe572007-07-07 19:25:05 +00003725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3727 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003728 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003729 } else {
3730 /* decode response */
3731 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003732 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003733 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003734 /* If rc should we check for EOPNOSUPP and
3735 disable the srvino flag? or in caller? */
3736 rc = -EIO; /* bad smb */
3737 else {
3738 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3739 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3740 struct file_chattr_info *pfinfo;
3741 /* BB Do we need a cast or hash here ? */
3742 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003743 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003744 rc = -EIO;
3745 goto GetExtAttrOut;
3746 }
3747 pfinfo = (struct file_chattr_info *)
3748 (data_offset + (char *) &pSMBr->hdr.Protocol);
3749 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003750 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003751 }
3752 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003753GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003754 cifs_buf_release(pSMB);
3755 if (rc == -EAGAIN)
3756 goto GetExtAttrRetry;
3757 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003758}
3759
Steve Frenchf654bac2005-04-28 22:41:04 -07003760#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
Jeff Layton79df1ba2010-12-06 12:52:08 -05003762#ifdef CONFIG_CIFS_ACL
3763/*
3764 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3765 * all NT TRANSACTS that we init here have total parm and data under about 400
3766 * bytes (to fit in small cifs buffer size), which is the case so far, it
3767 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3768 * returned setup area) and MaxParameterCount (returned parms size) must be set
3769 * by caller
3770 */
3771static int
3772smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003773 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003774 void **ret_buf)
3775{
3776 int rc;
3777 __u32 temp_offset;
3778 struct smb_com_ntransact_req *pSMB;
3779
3780 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3781 (void **)&pSMB);
3782 if (rc)
3783 return rc;
3784 *ret_buf = (void *)pSMB;
3785 pSMB->Reserved = 0;
3786 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3787 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003788 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003789 pSMB->ParameterCount = pSMB->TotalParameterCount;
3790 pSMB->DataCount = pSMB->TotalDataCount;
3791 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3792 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3793 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3794 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3795 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3796 pSMB->SubCommand = cpu_to_le16(sub_command);
3797 return 0;
3798}
3799
3800static int
3801validate_ntransact(char *buf, char **ppparm, char **ppdata,
3802 __u32 *pparmlen, __u32 *pdatalen)
3803{
3804 char *end_of_smb;
3805 __u32 data_count, data_offset, parm_count, parm_offset;
3806 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003807 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003808
3809 *pdatalen = 0;
3810 *pparmlen = 0;
3811
3812 if (buf == NULL)
3813 return -EINVAL;
3814
3815 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3816
Jeff Layton820a8032011-05-04 08:05:26 -04003817 bcc = get_bcc(&pSMBr->hdr);
3818 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003819 (char *)&pSMBr->ByteCount;
3820
3821 data_offset = le32_to_cpu(pSMBr->DataOffset);
3822 data_count = le32_to_cpu(pSMBr->DataCount);
3823 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3824 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3825
3826 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3827 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3828
3829 /* should we also check that parm and data areas do not overlap? */
3830 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003831 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003832 return -EINVAL;
3833 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003834 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003835 return -EINVAL;
3836 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003837 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003838 return -EINVAL;
3839 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003840 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3841 *ppdata, data_count, (data_count + *ppdata),
3842 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003843 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003844 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003845 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003846 return -EINVAL;
3847 }
3848 *pdatalen = data_count;
3849 *pparmlen = parm_count;
3850 return 0;
3851}
3852
Steve French0a4b92c2006-01-12 15:44:21 -08003853/* Get Security Descriptor (by handle) from remote server for a file or dir */
3854int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003855CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003856 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003857{
3858 int rc = 0;
3859 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003860 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003861 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003862 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003863
Joe Perchesf96637b2013-05-04 22:12:25 -05003864 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003865
Steve French630f3f0c2007-10-25 21:17:17 +00003866 *pbuflen = 0;
3867 *acl_inf = NULL;
3868
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003869 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003870 8 /* parm len */, tcon, (void **) &pSMB);
3871 if (rc)
3872 return rc;
3873
3874 pSMB->MaxParameterCount = cpu_to_le32(4);
3875 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3876 pSMB->MaxSetupCount = 0;
3877 pSMB->Fid = fid; /* file handle always le */
3878 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3879 CIFS_ACL_DACL);
3880 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003881 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003882 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003883 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003884
Steve Frencha761ac52007-10-18 21:45:27 +00003885 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003886 0, &rsp_iov);
3887 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003888 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003889 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003890 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003891 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003892 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003893 __u32 parm_len;
3894 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003895 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003896 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003897
3898/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003899 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003900 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003901 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003902 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003903 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003904
Joe Perchesf96637b2013-05-04 22:12:25 -05003905 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3906 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003907
3908 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3909 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003910 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003911 goto qsec_out;
3912 }
3913
3914/* BB check that data area is minimum length and as big as acl_len */
3915
Steve Frenchaf6f4612007-10-16 18:40:37 +00003916 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003917 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003918 cifs_dbg(VFS, "acl length %d does not match %d\n",
3919 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003920 if (*pbuflen > acl_len)
3921 *pbuflen = acl_len;
3922 }
Steve French0a4b92c2006-01-12 15:44:21 -08003923
Steve French630f3f0c2007-10-25 21:17:17 +00003924 /* check if buffer is big enough for the acl
3925 header followed by the smallest SID */
3926 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3927 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003928 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003929 rc = -EINVAL;
3930 *pbuflen = 0;
3931 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003932 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003933 if (*acl_inf == NULL) {
3934 *pbuflen = 0;
3935 rc = -ENOMEM;
3936 }
Steve French630f3f0c2007-10-25 21:17:17 +00003937 }
Steve French0a4b92c2006-01-12 15:44:21 -08003938 }
3939qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003940 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003941 return rc;
3942}
Steve French97837582007-12-31 07:47:21 +00003943
3944int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003945CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003946 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003947{
3948 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3949 int rc = 0;
3950 int bytes_returned = 0;
3951 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003952 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003953
3954setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003955 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003956 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003957 return rc;
Steve French97837582007-12-31 07:47:21 +00003958
3959 pSMB->MaxSetupCount = 0;
3960 pSMB->Reserved = 0;
3961
3962 param_count = 8;
3963 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3964 data_count = acllen;
3965 data_offset = param_offset + param_count;
3966 byte_count = 3 /* pad */ + param_count;
3967
3968 pSMB->DataCount = cpu_to_le32(data_count);
3969 pSMB->TotalDataCount = pSMB->DataCount;
3970 pSMB->MaxParameterCount = cpu_to_le32(4);
3971 pSMB->MaxDataCount = cpu_to_le32(16384);
3972 pSMB->ParameterCount = cpu_to_le32(param_count);
3973 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3974 pSMB->TotalParameterCount = pSMB->ParameterCount;
3975 pSMB->DataOffset = cpu_to_le32(data_offset);
3976 pSMB->SetupCount = 0;
3977 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3978 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3979
3980 pSMB->Fid = fid; /* file handle always le */
3981 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003982 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003983
3984 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003985 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3986 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003987 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003988 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003989 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003990
3991 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3992 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3993
Joe Perchesf96637b2013-05-04 22:12:25 -05003994 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3995 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003996 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003997 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003998 cifs_buf_release(pSMB);
3999
4000 if (rc == -EAGAIN)
4001 goto setCifsAclRetry;
4002
4003 return (rc);
4004}
4005
Jeff Layton79df1ba2010-12-06 12:52:08 -05004006#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004007
Steve French6b8edfe2005-08-23 20:26:03 -07004008/* Legacy Query Path Information call for lookup to old servers such
4009 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004010int
4011SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4012 const char *search_name, FILE_ALL_INFO *data,
4013 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004014{
Steve Frenchad7a2922008-02-07 23:25:02 +00004015 QUERY_INFORMATION_REQ *pSMB;
4016 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004017 int rc = 0;
4018 int bytes_returned;
4019 int name_len;
4020
Joe Perchesf96637b2013-05-04 22:12:25 -05004021 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004022QInfRetry:
4023 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004024 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004025 if (rc)
4026 return rc;
4027
4028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4029 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004030 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004031 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004032 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004033 name_len++; /* trailing null */
4034 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004035 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004036 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004037 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004038 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004039 }
4040 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004041 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004042 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004043 pSMB->ByteCount = cpu_to_le16(name_len);
4044
4045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004047 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004048 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004049 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004050 struct timespec ts;
4051 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004052
4053 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004054 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004055 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004056 ts.tv_nsec = 0;
4057 ts.tv_sec = time;
4058 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004059 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4060 data->LastWriteTime = data->ChangeTime;
4061 data->LastAccessTime = 0;
4062 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004063 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004064 data->EndOfFile = data->AllocationSize;
4065 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004066 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004067 } else
4068 rc = -EIO; /* bad buffer passed in */
4069
4070 cifs_buf_release(pSMB);
4071
4072 if (rc == -EAGAIN)
4073 goto QInfRetry;
4074
4075 return rc;
4076}
4077
Jeff Laytonbcd53572010-02-12 07:44:16 -05004078int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004079CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004080 u16 netfid, FILE_ALL_INFO *pFindData)
4081{
4082 struct smb_t2_qfi_req *pSMB = NULL;
4083 struct smb_t2_qfi_rsp *pSMBr = NULL;
4084 int rc = 0;
4085 int bytes_returned;
4086 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004087
Jeff Laytonbcd53572010-02-12 07:44:16 -05004088QFileInfoRetry:
4089 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4090 (void **) &pSMBr);
4091 if (rc)
4092 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004093
Jeff Laytonbcd53572010-02-12 07:44:16 -05004094 params = 2 /* level */ + 2 /* fid */;
4095 pSMB->t2.TotalDataCount = 0;
4096 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4097 /* BB find exact max data count below from sess structure BB */
4098 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4099 pSMB->t2.MaxSetupCount = 0;
4100 pSMB->t2.Reserved = 0;
4101 pSMB->t2.Flags = 0;
4102 pSMB->t2.Timeout = 0;
4103 pSMB->t2.Reserved2 = 0;
4104 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4105 Fid) - 4);
4106 pSMB->t2.DataCount = 0;
4107 pSMB->t2.DataOffset = 0;
4108 pSMB->t2.SetupCount = 1;
4109 pSMB->t2.Reserved3 = 0;
4110 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4111 byte_count = params + 1 /* pad */ ;
4112 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4113 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4114 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4115 pSMB->Pad = 0;
4116 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004117 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004118 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004119
4120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4121 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4122 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004123 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004124 } else { /* decode response */
4125 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4126
4127 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4128 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004129 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004130 rc = -EIO; /* bad smb */
4131 else if (pFindData) {
4132 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4133 memcpy((char *) pFindData,
4134 (char *) &pSMBr->hdr.Protocol +
4135 data_offset, sizeof(FILE_ALL_INFO));
4136 } else
4137 rc = -ENOMEM;
4138 }
4139 cifs_buf_release(pSMB);
4140 if (rc == -EAGAIN)
4141 goto QFileInfoRetry;
4142
4143 return rc;
4144}
Steve French6b8edfe2005-08-23 20:26:03 -07004145
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004147CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004148 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004149 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004150 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004152 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 TRANSACTION2_QPI_REQ *pSMB = NULL;
4154 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4155 int rc = 0;
4156 int bytes_returned;
4157 int name_len;
4158 __u16 params, byte_count;
4159
Joe Perchesf96637b2013-05-04 22:12:25 -05004160 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161QPathInfoRetry:
4162 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4163 (void **) &pSMBr);
4164 if (rc)
4165 return rc;
4166
4167 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4168 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004169 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004170 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 name_len++; /* trailing null */
4172 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004173 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004174 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004176 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 }
4178
Steve French50c2f752007-07-13 00:33:32 +00004179 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 pSMB->TotalDataCount = 0;
4181 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004182 /* BB find exact max SMB PDU from sess structure BB */
4183 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 pSMB->MaxSetupCount = 0;
4185 pSMB->Reserved = 0;
4186 pSMB->Flags = 0;
4187 pSMB->Timeout = 0;
4188 pSMB->Reserved2 = 0;
4189 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004190 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 pSMB->DataCount = 0;
4192 pSMB->DataOffset = 0;
4193 pSMB->SetupCount = 1;
4194 pSMB->Reserved3 = 0;
4195 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4196 byte_count = params + 1 /* pad */ ;
4197 pSMB->TotalParameterCount = cpu_to_le16(params);
4198 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004199 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004200 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4201 else
4202 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004204 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 pSMB->ByteCount = cpu_to_le16(byte_count);
4206
4207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4209 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004210 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 } else { /* decode response */
4212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4213
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004214 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4215 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004216 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004218 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004219 rc = -EIO; /* 24 or 26 expected but we do not read
4220 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004221 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004222 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004224
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004225 /*
4226 * On legacy responses we do not read the last field,
4227 * EAsize, fortunately since it varies by subdialect and
4228 * also note it differs on Set vs Get, ie two bytes or 4
4229 * bytes depending but we don't care here.
4230 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004231 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004232 size = sizeof(FILE_INFO_STANDARD);
4233 else
4234 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004235 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004236 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 } else
4238 rc = -ENOMEM;
4239 }
4240 cifs_buf_release(pSMB);
4241 if (rc == -EAGAIN)
4242 goto QPathInfoRetry;
4243
4244 return rc;
4245}
4246
4247int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004248CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004249 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4250{
4251 struct smb_t2_qfi_req *pSMB = NULL;
4252 struct smb_t2_qfi_rsp *pSMBr = NULL;
4253 int rc = 0;
4254 int bytes_returned;
4255 __u16 params, byte_count;
4256
4257UnixQFileInfoRetry:
4258 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4259 (void **) &pSMBr);
4260 if (rc)
4261 return rc;
4262
4263 params = 2 /* level */ + 2 /* fid */;
4264 pSMB->t2.TotalDataCount = 0;
4265 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4266 /* BB find exact max data count below from sess structure BB */
4267 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4268 pSMB->t2.MaxSetupCount = 0;
4269 pSMB->t2.Reserved = 0;
4270 pSMB->t2.Flags = 0;
4271 pSMB->t2.Timeout = 0;
4272 pSMB->t2.Reserved2 = 0;
4273 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4274 Fid) - 4);
4275 pSMB->t2.DataCount = 0;
4276 pSMB->t2.DataOffset = 0;
4277 pSMB->t2.SetupCount = 1;
4278 pSMB->t2.Reserved3 = 0;
4279 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4280 byte_count = params + 1 /* pad */ ;
4281 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4282 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4283 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4284 pSMB->Pad = 0;
4285 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004286 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004287 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004288
4289 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4290 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4291 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004292 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004293 } else { /* decode response */
4294 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4295
Jeff Layton820a8032011-05-04 08:05:26 -04004296 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004297 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 -05004298 rc = -EIO; /* bad smb */
4299 } else {
4300 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4301 memcpy((char *) pFindData,
4302 (char *) &pSMBr->hdr.Protocol +
4303 data_offset,
4304 sizeof(FILE_UNIX_BASIC_INFO));
4305 }
4306 }
4307
4308 cifs_buf_release(pSMB);
4309 if (rc == -EAGAIN)
4310 goto UnixQFileInfoRetry;
4311
4312 return rc;
4313}
4314
4315int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004316CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004318 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004319 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320{
4321/* SMB_QUERY_FILE_UNIX_BASIC */
4322 TRANSACTION2_QPI_REQ *pSMB = NULL;
4323 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4324 int rc = 0;
4325 int bytes_returned = 0;
4326 int name_len;
4327 __u16 params, byte_count;
4328
Joe Perchesf96637b2013-05-04 22:12:25 -05004329 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330UnixQPathInfoRetry:
4331 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4332 (void **) &pSMBr);
4333 if (rc)
4334 return rc;
4335
4336 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4337 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004338 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4339 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 name_len++; /* trailing null */
4341 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004342 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 name_len = strnlen(searchName, PATH_MAX);
4344 name_len++; /* trailing null */
4345 strncpy(pSMB->FileName, searchName, name_len);
4346 }
4347
Steve French50c2f752007-07-13 00:33:32 +00004348 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 pSMB->TotalDataCount = 0;
4350 pSMB->MaxParameterCount = cpu_to_le16(2);
4351 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004352 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 pSMB->MaxSetupCount = 0;
4354 pSMB->Reserved = 0;
4355 pSMB->Flags = 0;
4356 pSMB->Timeout = 0;
4357 pSMB->Reserved2 = 0;
4358 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004359 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 pSMB->DataCount = 0;
4361 pSMB->DataOffset = 0;
4362 pSMB->SetupCount = 1;
4363 pSMB->Reserved3 = 0;
4364 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4365 byte_count = params + 1 /* pad */ ;
4366 pSMB->TotalParameterCount = cpu_to_le16(params);
4367 pSMB->ParameterCount = pSMB->TotalParameterCount;
4368 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4369 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004370 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 pSMB->ByteCount = cpu_to_le16(byte_count);
4372
4373 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4374 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4375 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004376 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 } else { /* decode response */
4378 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4379
Jeff Layton820a8032011-05-04 08:05:26 -04004380 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004381 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 -07004382 rc = -EIO; /* bad smb */
4383 } else {
4384 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4385 memcpy((char *) pFindData,
4386 (char *) &pSMBr->hdr.Protocol +
4387 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004388 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 }
4390 }
4391 cifs_buf_release(pSMB);
4392 if (rc == -EAGAIN)
4393 goto UnixQPathInfoRetry;
4394
4395 return rc;
4396}
4397
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398/* xid, tcon, searchName and codepage are input parms, rest are returned */
4399int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004400CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004401 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004402 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004403 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404{
4405/* level 257 SMB_ */
4406 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4407 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004408 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 int rc = 0;
4410 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004411 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004413 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414
Joe Perchesf96637b2013-05-04 22:12:25 -05004415 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
4417findFirstRetry:
4418 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4419 (void **) &pSMBr);
4420 if (rc)
4421 return rc;
4422
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004423 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004424 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004425
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4427 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004428 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4429 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004430 /* We can not add the asterik earlier in case
4431 it got remapped to 0xF03A as if it were part of the
4432 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004434 if (msearch) {
4435 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4436 pSMB->FileName[name_len+1] = 0;
4437 pSMB->FileName[name_len+2] = '*';
4438 pSMB->FileName[name_len+3] = 0;
4439 name_len += 4; /* now the trailing null */
4440 /* null terminate just in case */
4441 pSMB->FileName[name_len] = 0;
4442 pSMB->FileName[name_len+1] = 0;
4443 name_len += 2;
4444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 } else { /* BB add check for overrun of SMB buf BB */
4446 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004448 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 free buffer exit; BB */
4450 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004451 if (msearch) {
4452 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4453 pSMB->FileName[name_len+1] = '*';
4454 pSMB->FileName[name_len+2] = 0;
4455 name_len += 3;
4456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 }
4458
4459 params = 12 + name_len /* includes null */ ;
4460 pSMB->TotalDataCount = 0; /* no EAs */
4461 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004462 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 pSMB->MaxSetupCount = 0;
4464 pSMB->Reserved = 0;
4465 pSMB->Flags = 0;
4466 pSMB->Timeout = 0;
4467 pSMB->Reserved2 = 0;
4468 byte_count = params + 1 /* pad */ ;
4469 pSMB->TotalParameterCount = cpu_to_le16(params);
4470 pSMB->ParameterCount = pSMB->TotalParameterCount;
4471 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004472 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4473 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 pSMB->DataCount = 0;
4475 pSMB->DataOffset = 0;
4476 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4477 pSMB->Reserved3 = 0;
4478 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4479 pSMB->SearchAttributes =
4480 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4481 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004482 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004483 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4485
4486 /* BB what should we set StorageType to? Does it matter? BB */
4487 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004488 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 pSMB->ByteCount = cpu_to_le16(byte_count);
4490
4491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004493 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Steve French88274812006-03-09 22:21:45 +00004495 if (rc) {/* BB add logic to retry regular search if Unix search
4496 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004498 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004499
Steve French88274812006-03-09 22:21:45 +00004500 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501
4502 /* BB eventually could optimize out free and realloc of buf */
4503 /* for this case */
4504 if (rc == -EAGAIN)
4505 goto findFirstRetry;
4506 } else { /* decode response */
4507 /* BB remember to free buffer if error BB */
4508 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004509 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004510 unsigned int lnoff;
4511
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004513 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 else
Steve French4b18f2a2008-04-29 00:06:05 +00004515 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516
4517 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004518 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004519 psrch_inf->srch_entries_start =
4520 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4523 le16_to_cpu(pSMBr->t2.ParameterOffset));
4524
Steve French790fe572007-07-07 19:25:05 +00004525 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004526 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 else
Steve French4b18f2a2008-04-29 00:06:05 +00004528 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529
Steve French50c2f752007-07-13 00:33:32 +00004530 psrch_inf->entries_in_buffer =
4531 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004532 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004534 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004535 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004536 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004537 psrch_inf->last_entry = NULL;
4538 return rc;
4539 }
4540
Steve French0752f152008-10-07 20:03:33 +00004541 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004542 lnoff;
4543
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004544 if (pnetfid)
4545 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 } else {
4547 cifs_buf_release(pSMB);
4548 }
4549 }
4550
4551 return rc;
4552}
4553
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004554int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4555 __u16 searchHandle, __u16 search_flags,
4556 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557{
4558 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4559 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004560 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 char *response_data;
4562 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004563 int bytes_returned;
4564 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 __u16 params, byte_count;
4566
Joe Perchesf96637b2013-05-04 22:12:25 -05004567 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568
Steve French4b18f2a2008-04-29 00:06:05 +00004569 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 return -ENOENT;
4571
4572 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4573 (void **) &pSMBr);
4574 if (rc)
4575 return rc;
4576
Steve French50c2f752007-07-13 00:33:32 +00004577 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 byte_count = 0;
4579 pSMB->TotalDataCount = 0; /* no EAs */
4580 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004581 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 pSMB->MaxSetupCount = 0;
4583 pSMB->Reserved = 0;
4584 pSMB->Flags = 0;
4585 pSMB->Timeout = 0;
4586 pSMB->Reserved2 = 0;
4587 pSMB->ParameterOffset = cpu_to_le16(
4588 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4589 pSMB->DataCount = 0;
4590 pSMB->DataOffset = 0;
4591 pSMB->SetupCount = 1;
4592 pSMB->Reserved3 = 0;
4593 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4594 pSMB->SearchHandle = searchHandle; /* always kept as le */
4595 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004596 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4598 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004599 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600
4601 name_len = psrch_inf->resume_name_len;
4602 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004603 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4605 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004606 /* 14 byte parm len above enough for 2 byte null terminator */
4607 pSMB->ResumeFileName[name_len] = 0;
4608 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 } else {
4610 rc = -EINVAL;
4611 goto FNext2_err_exit;
4612 }
4613 byte_count = params + 1 /* pad */ ;
4614 pSMB->TotalParameterCount = cpu_to_le16(params);
4615 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004616 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004618
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4620 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004621 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 if (rc) {
4623 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004624 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004625 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004626 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004628 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 } else { /* decode response */
4630 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004631
Steve French790fe572007-07-07 19:25:05 +00004632 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004633 unsigned int lnoff;
4634
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 /* BB fixme add lock for file (srch_info) struct here */
4636 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004637 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 else
Steve French4b18f2a2008-04-29 00:06:05 +00004639 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 response_data = (char *) &pSMBr->hdr.Protocol +
4641 le16_to_cpu(pSMBr->t2.ParameterOffset);
4642 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4643 response_data = (char *)&pSMBr->hdr.Protocol +
4644 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004645 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004646 cifs_small_buf_release(
4647 psrch_inf->ntwrk_buf_start);
4648 else
4649 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 psrch_inf->srch_entries_start = response_data;
4651 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004652 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004653 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004654 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 else
Steve French4b18f2a2008-04-29 00:06:05 +00004656 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004657 psrch_inf->entries_in_buffer =
4658 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 psrch_inf->index_of_last_entry +=
4660 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004661 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004662 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004663 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004664 psrch_inf->last_entry = NULL;
4665 return rc;
4666 } else
4667 psrch_inf->last_entry =
4668 psrch_inf->srch_entries_start + lnoff;
4669
Joe Perchesf96637b2013-05-04 22:12:25 -05004670/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4671 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672
4673 /* BB fixme add unlock here */
4674 }
4675
4676 }
4677
4678 /* BB On error, should we leave previous search buf (and count and
4679 last entry fields) intact or free the previous one? */
4680
4681 /* Note: On -EAGAIN error only caller can retry on handle based calls
4682 since file handle passed in no longer valid */
4683FNext2_err_exit:
4684 if (rc != 0)
4685 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 return rc;
4687}
4688
4689int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004690CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004691 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692{
4693 int rc = 0;
4694 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695
Joe Perchesf96637b2013-05-04 22:12:25 -05004696 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4698
4699 /* no sense returning error if session restarted
4700 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004701 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 return 0;
4703 if (rc)
4704 return rc;
4705
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 pSMB->FileID = searchHandle;
4707 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004708 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004709 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004710 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004711 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004712
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004713 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714
4715 /* Since session is dead, search handle closed on server already */
4716 if (rc == -EAGAIN)
4717 rc = 0;
4718
4719 return rc;
4720}
4721
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004723CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004724 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004725 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726{
4727 int rc = 0;
4728 TRANSACTION2_QPI_REQ *pSMB = NULL;
4729 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4730 int name_len, bytes_returned;
4731 __u16 params, byte_count;
4732
Joe Perchesf96637b2013-05-04 22:12:25 -05004733 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004734 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004735 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736
4737GetInodeNumberRetry:
4738 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004739 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 if (rc)
4741 return rc;
4742
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4744 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004745 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004746 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004747 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 name_len++; /* trailing null */
4749 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004750 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004751 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004753 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 }
4755
4756 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4757 pSMB->TotalDataCount = 0;
4758 pSMB->MaxParameterCount = cpu_to_le16(2);
4759 /* BB find exact max data count below from sess structure BB */
4760 pSMB->MaxDataCount = cpu_to_le16(4000);
4761 pSMB->MaxSetupCount = 0;
4762 pSMB->Reserved = 0;
4763 pSMB->Flags = 0;
4764 pSMB->Timeout = 0;
4765 pSMB->Reserved2 = 0;
4766 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004767 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 pSMB->DataCount = 0;
4769 pSMB->DataOffset = 0;
4770 pSMB->SetupCount = 1;
4771 pSMB->Reserved3 = 0;
4772 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4773 byte_count = params + 1 /* pad */ ;
4774 pSMB->TotalParameterCount = cpu_to_le16(params);
4775 pSMB->ParameterCount = pSMB->TotalParameterCount;
4776 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4777 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004778 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 pSMB->ByteCount = cpu_to_le16(byte_count);
4780
4781 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4782 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4783 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004784 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 } else {
4786 /* decode response */
4787 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004789 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 /* If rc should we check for EOPNOSUPP and
4791 disable the srvino flag? or in caller? */
4792 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004793 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4795 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004796 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004798 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004799 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 rc = -EIO;
4801 goto GetInodeNumOut;
4802 }
4803 pfinfo = (struct file_internal_info *)
4804 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004805 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 }
4807 }
4808GetInodeNumOut:
4809 cifs_buf_release(pSMB);
4810 if (rc == -EAGAIN)
4811 goto GetInodeNumberRetry;
4812 return rc;
4813}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814
4815int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004816CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004817 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004818 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820{
4821/* TRANS2_GET_DFS_REFERRAL */
4822 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4823 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 int rc = 0;
4825 int bytes_returned;
4826 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004828 *num_of_nodes = 0;
4829 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
Joe Perchesf96637b2013-05-04 22:12:25 -05004831 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 if (ses == NULL)
4833 return -ENODEV;
4834getDFSRetry:
4835 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4836 (void **) &pSMBr);
4837 if (rc)
4838 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004839
4840 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004841 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004842 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 pSMB->hdr.Tid = ses->ipc_tid;
4844 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004845 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004847 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
4850 if (ses->capabilities & CAP_UNICODE) {
4851 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4852 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004853 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004854 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004855 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 name_len++; /* trailing null */
4857 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004858 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004859 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004861 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 }
4863
Dan Carpenter65c3b202015-04-30 17:30:24 +03004864 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004865 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004866
Steve French50c2f752007-07-13 00:33:32 +00004867 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004868
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 params = 2 /* level */ + name_len /*includes null */ ;
4870 pSMB->TotalDataCount = 0;
4871 pSMB->DataCount = 0;
4872 pSMB->DataOffset = 0;
4873 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004874 /* BB find exact max SMB PDU from sess structure BB */
4875 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 pSMB->MaxSetupCount = 0;
4877 pSMB->Reserved = 0;
4878 pSMB->Flags = 0;
4879 pSMB->Timeout = 0;
4880 pSMB->Reserved2 = 0;
4881 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004882 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 pSMB->SetupCount = 1;
4884 pSMB->Reserved3 = 0;
4885 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4886 byte_count = params + 3 /* pad */ ;
4887 pSMB->ParameterCount = cpu_to_le16(params);
4888 pSMB->TotalParameterCount = pSMB->ParameterCount;
4889 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004890 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->ByteCount = cpu_to_le16(byte_count);
4892
4893 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4895 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004896 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004897 goto GetDFSRefExit;
4898 }
4899 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004901 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004902 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004903 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004904 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004906
Joe Perchesf96637b2013-05-04 22:12:25 -05004907 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4908 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004909
4910 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004911 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4912 le16_to_cpu(pSMBr->t2.DataCount),
4913 num_of_nodes, target_nodes, nls_codepage,
4914 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004915 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004916
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004918 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919
4920 if (rc == -EAGAIN)
4921 goto getDFSRetry;
4922
4923 return rc;
4924}
4925
Steve French20962432005-09-21 22:05:57 -07004926/* Query File System Info such as free space to old servers such as Win 9x */
4927int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004928SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4929 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004930{
4931/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4932 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4933 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4934 FILE_SYSTEM_ALLOC_INFO *response_data;
4935 int rc = 0;
4936 int bytes_returned = 0;
4937 __u16 params, byte_count;
4938
Joe Perchesf96637b2013-05-04 22:12:25 -05004939 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004940oldQFSInfoRetry:
4941 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4942 (void **) &pSMBr);
4943 if (rc)
4944 return rc;
Steve French20962432005-09-21 22:05:57 -07004945
4946 params = 2; /* level */
4947 pSMB->TotalDataCount = 0;
4948 pSMB->MaxParameterCount = cpu_to_le16(2);
4949 pSMB->MaxDataCount = cpu_to_le16(1000);
4950 pSMB->MaxSetupCount = 0;
4951 pSMB->Reserved = 0;
4952 pSMB->Flags = 0;
4953 pSMB->Timeout = 0;
4954 pSMB->Reserved2 = 0;
4955 byte_count = params + 1 /* pad */ ;
4956 pSMB->TotalParameterCount = cpu_to_le16(params);
4957 pSMB->ParameterCount = pSMB->TotalParameterCount;
4958 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4959 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4960 pSMB->DataCount = 0;
4961 pSMB->DataOffset = 0;
4962 pSMB->SetupCount = 1;
4963 pSMB->Reserved3 = 0;
4964 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4965 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004966 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004967 pSMB->ByteCount = cpu_to_le16(byte_count);
4968
4969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4971 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004972 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004973 } else { /* decode response */
4974 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4975
Jeff Layton820a8032011-05-04 08:05:26 -04004976 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004977 rc = -EIO; /* bad smb */
4978 else {
4979 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004980 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004981 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004982
Steve French50c2f752007-07-13 00:33:32 +00004983 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004984 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4985 FSData->f_bsize =
4986 le16_to_cpu(response_data->BytesPerSector) *
4987 le32_to_cpu(response_data->
4988 SectorsPerAllocationUnit);
4989 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004990 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004991 FSData->f_bfree = FSData->f_bavail =
4992 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004993 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4994 (unsigned long long)FSData->f_blocks,
4995 (unsigned long long)FSData->f_bfree,
4996 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004997 }
4998 }
4999 cifs_buf_release(pSMB);
5000
5001 if (rc == -EAGAIN)
5002 goto oldQFSInfoRetry;
5003
5004 return rc;
5005}
5006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005008CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5009 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010{
5011/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5012 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5013 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5014 FILE_SYSTEM_INFO *response_data;
5015 int rc = 0;
5016 int bytes_returned = 0;
5017 __u16 params, byte_count;
5018
Joe Perchesf96637b2013-05-04 22:12:25 -05005019 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020QFSInfoRetry:
5021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5022 (void **) &pSMBr);
5023 if (rc)
5024 return rc;
5025
5026 params = 2; /* level */
5027 pSMB->TotalDataCount = 0;
5028 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005029 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 pSMB->MaxSetupCount = 0;
5031 pSMB->Reserved = 0;
5032 pSMB->Flags = 0;
5033 pSMB->Timeout = 0;
5034 pSMB->Reserved2 = 0;
5035 byte_count = params + 1 /* pad */ ;
5036 pSMB->TotalParameterCount = cpu_to_le16(params);
5037 pSMB->ParameterCount = pSMB->TotalParameterCount;
5038 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005039 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 pSMB->DataCount = 0;
5041 pSMB->DataOffset = 0;
5042 pSMB->SetupCount = 1;
5043 pSMB->Reserved3 = 0;
5044 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5045 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005046 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 pSMB->ByteCount = cpu_to_le16(byte_count);
5048
5049 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5050 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5051 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005052 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005054 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055
Jeff Layton820a8032011-05-04 08:05:26 -04005056 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 rc = -EIO; /* bad smb */
5058 else {
5059 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060
5061 response_data =
5062 (FILE_SYSTEM_INFO
5063 *) (((char *) &pSMBr->hdr.Protocol) +
5064 data_offset);
5065 FSData->f_bsize =
5066 le32_to_cpu(response_data->BytesPerSector) *
5067 le32_to_cpu(response_data->
5068 SectorsPerAllocationUnit);
5069 FSData->f_blocks =
5070 le64_to_cpu(response_data->TotalAllocationUnits);
5071 FSData->f_bfree = FSData->f_bavail =
5072 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005073 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5074 (unsigned long long)FSData->f_blocks,
5075 (unsigned long long)FSData->f_bfree,
5076 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 }
5078 }
5079 cifs_buf_release(pSMB);
5080
5081 if (rc == -EAGAIN)
5082 goto QFSInfoRetry;
5083
5084 return rc;
5085}
5086
5087int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005088CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089{
5090/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5091 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5092 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5093 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5094 int rc = 0;
5095 int bytes_returned = 0;
5096 __u16 params, byte_count;
5097
Joe Perchesf96637b2013-05-04 22:12:25 -05005098 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099QFSAttributeRetry:
5100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5101 (void **) &pSMBr);
5102 if (rc)
5103 return rc;
5104
5105 params = 2; /* level */
5106 pSMB->TotalDataCount = 0;
5107 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005108 /* BB find exact max SMB PDU from sess structure BB */
5109 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 pSMB->MaxSetupCount = 0;
5111 pSMB->Reserved = 0;
5112 pSMB->Flags = 0;
5113 pSMB->Timeout = 0;
5114 pSMB->Reserved2 = 0;
5115 byte_count = params + 1 /* pad */ ;
5116 pSMB->TotalParameterCount = cpu_to_le16(params);
5117 pSMB->ParameterCount = pSMB->TotalParameterCount;
5118 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005119 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 pSMB->DataCount = 0;
5121 pSMB->DataOffset = 0;
5122 pSMB->SetupCount = 1;
5123 pSMB->Reserved3 = 0;
5124 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5125 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005126 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 pSMB->ByteCount = cpu_to_le16(byte_count);
5128
5129 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5130 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5131 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005132 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 } else { /* decode response */
5134 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5135
Jeff Layton820a8032011-05-04 08:05:26 -04005136 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005137 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 rc = -EIO; /* bad smb */
5139 } else {
5140 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5141 response_data =
5142 (FILE_SYSTEM_ATTRIBUTE_INFO
5143 *) (((char *) &pSMBr->hdr.Protocol) +
5144 data_offset);
5145 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005146 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 }
5148 }
5149 cifs_buf_release(pSMB);
5150
5151 if (rc == -EAGAIN)
5152 goto QFSAttributeRetry;
5153
5154 return rc;
5155}
5156
5157int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005158CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159{
5160/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5161 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5162 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5163 FILE_SYSTEM_DEVICE_INFO *response_data;
5164 int rc = 0;
5165 int bytes_returned = 0;
5166 __u16 params, byte_count;
5167
Joe Perchesf96637b2013-05-04 22:12:25 -05005168 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169QFSDeviceRetry:
5170 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5171 (void **) &pSMBr);
5172 if (rc)
5173 return rc;
5174
5175 params = 2; /* level */
5176 pSMB->TotalDataCount = 0;
5177 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005178 /* BB find exact max SMB PDU from sess structure BB */
5179 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 pSMB->MaxSetupCount = 0;
5181 pSMB->Reserved = 0;
5182 pSMB->Flags = 0;
5183 pSMB->Timeout = 0;
5184 pSMB->Reserved2 = 0;
5185 byte_count = params + 1 /* pad */ ;
5186 pSMB->TotalParameterCount = cpu_to_le16(params);
5187 pSMB->ParameterCount = pSMB->TotalParameterCount;
5188 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005189 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190
5191 pSMB->DataCount = 0;
5192 pSMB->DataOffset = 0;
5193 pSMB->SetupCount = 1;
5194 pSMB->Reserved3 = 0;
5195 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5196 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005197 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 pSMB->ByteCount = cpu_to_le16(byte_count);
5199
5200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5202 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005203 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 } else { /* decode response */
5205 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5206
Jeff Layton820a8032011-05-04 08:05:26 -04005207 if (rc || get_bcc(&pSMBr->hdr) <
5208 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 rc = -EIO; /* bad smb */
5210 else {
5211 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5212 response_data =
Steve French737b7582005-04-28 22:41:06 -07005213 (FILE_SYSTEM_DEVICE_INFO *)
5214 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 data_offset);
5216 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005217 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 }
5219 }
5220 cifs_buf_release(pSMB);
5221
5222 if (rc == -EAGAIN)
5223 goto QFSDeviceRetry;
5224
5225 return rc;
5226}
5227
5228int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005229CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230{
5231/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5232 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5233 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5234 FILE_SYSTEM_UNIX_INFO *response_data;
5235 int rc = 0;
5236 int bytes_returned = 0;
5237 __u16 params, byte_count;
5238
Joe Perchesf96637b2013-05-04 22:12:25 -05005239 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005241 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5242 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 if (rc)
5244 return rc;
5245
5246 params = 2; /* level */
5247 pSMB->TotalDataCount = 0;
5248 pSMB->DataCount = 0;
5249 pSMB->DataOffset = 0;
5250 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005251 /* BB find exact max SMB PDU from sess structure BB */
5252 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 pSMB->MaxSetupCount = 0;
5254 pSMB->Reserved = 0;
5255 pSMB->Flags = 0;
5256 pSMB->Timeout = 0;
5257 pSMB->Reserved2 = 0;
5258 byte_count = params + 1 /* pad */ ;
5259 pSMB->ParameterCount = cpu_to_le16(params);
5260 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005261 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5262 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 pSMB->SetupCount = 1;
5264 pSMB->Reserved3 = 0;
5265 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5266 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005267 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 pSMB->ByteCount = cpu_to_le16(byte_count);
5269
5270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5272 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005273 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 } else { /* decode response */
5275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5276
Jeff Layton820a8032011-05-04 08:05:26 -04005277 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 rc = -EIO; /* bad smb */
5279 } else {
5280 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5281 response_data =
5282 (FILE_SYSTEM_UNIX_INFO
5283 *) (((char *) &pSMBr->hdr.Protocol) +
5284 data_offset);
5285 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005286 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 }
5288 }
5289 cifs_buf_release(pSMB);
5290
5291 if (rc == -EAGAIN)
5292 goto QFSUnixRetry;
5293
5294
5295 return rc;
5296}
5297
Jeremy Allisonac670552005-06-22 17:26:35 -07005298int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005299CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005300{
5301/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5302 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5303 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5304 int rc = 0;
5305 int bytes_returned = 0;
5306 __u16 params, param_offset, offset, byte_count;
5307
Joe Perchesf96637b2013-05-04 22:12:25 -05005308 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005309SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005310 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005311 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5312 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005313 if (rc)
5314 return rc;
5315
5316 params = 4; /* 2 bytes zero followed by info level. */
5317 pSMB->MaxSetupCount = 0;
5318 pSMB->Reserved = 0;
5319 pSMB->Flags = 0;
5320 pSMB->Timeout = 0;
5321 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005322 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5323 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005324 offset = param_offset + params;
5325
5326 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005327 /* BB find exact max SMB PDU from sess structure BB */
5328 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005329 pSMB->SetupCount = 1;
5330 pSMB->Reserved3 = 0;
5331 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5332 byte_count = 1 /* pad */ + params + 12;
5333
5334 pSMB->DataCount = cpu_to_le16(12);
5335 pSMB->ParameterCount = cpu_to_le16(params);
5336 pSMB->TotalDataCount = pSMB->DataCount;
5337 pSMB->TotalParameterCount = pSMB->ParameterCount;
5338 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5339 pSMB->DataOffset = cpu_to_le16(offset);
5340
5341 /* Params. */
5342 pSMB->FileNum = 0;
5343 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5344
5345 /* Data. */
5346 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5347 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5348 pSMB->ClientUnixCap = cpu_to_le64(cap);
5349
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005350 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005351 pSMB->ByteCount = cpu_to_le16(byte_count);
5352
5353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5355 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005356 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005357 } else { /* decode response */
5358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005359 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005360 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005361 }
5362 cifs_buf_release(pSMB);
5363
5364 if (rc == -EAGAIN)
5365 goto SETFSUnixRetry;
5366
5367 return rc;
5368}
5369
5370
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371
5372int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005373CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005374 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375{
5376/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5377 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5378 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5379 FILE_SYSTEM_POSIX_INFO *response_data;
5380 int rc = 0;
5381 int bytes_returned = 0;
5382 __u16 params, byte_count;
5383
Joe Perchesf96637b2013-05-04 22:12:25 -05005384 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385QFSPosixRetry:
5386 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5387 (void **) &pSMBr);
5388 if (rc)
5389 return rc;
5390
5391 params = 2; /* level */
5392 pSMB->TotalDataCount = 0;
5393 pSMB->DataCount = 0;
5394 pSMB->DataOffset = 0;
5395 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005396 /* BB find exact max SMB PDU from sess structure BB */
5397 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 pSMB->MaxSetupCount = 0;
5399 pSMB->Reserved = 0;
5400 pSMB->Flags = 0;
5401 pSMB->Timeout = 0;
5402 pSMB->Reserved2 = 0;
5403 byte_count = params + 1 /* pad */ ;
5404 pSMB->ParameterCount = cpu_to_le16(params);
5405 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005406 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5407 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 pSMB->SetupCount = 1;
5409 pSMB->Reserved3 = 0;
5410 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5411 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005412 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413 pSMB->ByteCount = cpu_to_le16(byte_count);
5414
5415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5417 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005418 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 } else { /* decode response */
5420 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5421
Jeff Layton820a8032011-05-04 08:05:26 -04005422 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 rc = -EIO; /* bad smb */
5424 } else {
5425 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5426 response_data =
5427 (FILE_SYSTEM_POSIX_INFO
5428 *) (((char *) &pSMBr->hdr.Protocol) +
5429 data_offset);
5430 FSData->f_bsize =
5431 le32_to_cpu(response_data->BlockSize);
5432 FSData->f_blocks =
5433 le64_to_cpu(response_data->TotalBlocks);
5434 FSData->f_bfree =
5435 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005436 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 FSData->f_bavail = FSData->f_bfree;
5438 } else {
5439 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005440 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 }
Steve French790fe572007-07-07 19:25:05 +00005442 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005444 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005445 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005447 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 }
5449 }
5450 cifs_buf_release(pSMB);
5451
5452 if (rc == -EAGAIN)
5453 goto QFSPosixRetry;
5454
5455 return rc;
5456}
5457
5458
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005459/*
5460 * We can not use write of zero bytes trick to set file size due to need for
5461 * large file support. Also note that this SetPathInfo is preferred to
5462 * SetFileInfo based method in next routine which is only needed to work around
5463 * a sharing violation bugin Samba which this routine can run into.
5464 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005466CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005467 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5468 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469{
5470 struct smb_com_transaction2_spi_req *pSMB = NULL;
5471 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5472 struct file_end_of_file_info *parm_data;
5473 int name_len;
5474 int rc = 0;
5475 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005476 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005477
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 __u16 params, byte_count, data_count, param_offset, offset;
5479
Joe Perchesf96637b2013-05-04 22:12:25 -05005480 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481SetEOFRetry:
5482 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5483 (void **) &pSMBr);
5484 if (rc)
5485 return rc;
5486
5487 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5488 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005489 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5490 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 name_len++; /* trailing null */
5492 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005493 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005494 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005496 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 }
5498 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005499 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005501 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 pSMB->MaxSetupCount = 0;
5503 pSMB->Reserved = 0;
5504 pSMB->Flags = 0;
5505 pSMB->Timeout = 0;
5506 pSMB->Reserved2 = 0;
5507 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005508 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005510 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005511 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5512 pSMB->InformationLevel =
5513 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5514 else
5515 pSMB->InformationLevel =
5516 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5517 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5519 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005520 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 else
5522 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005523 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 }
5525
5526 parm_data =
5527 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5528 offset);
5529 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5530 pSMB->DataOffset = cpu_to_le16(offset);
5531 pSMB->SetupCount = 1;
5532 pSMB->Reserved3 = 0;
5533 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5534 byte_count = 3 /* pad */ + params + data_count;
5535 pSMB->DataCount = cpu_to_le16(data_count);
5536 pSMB->TotalDataCount = pSMB->DataCount;
5537 pSMB->ParameterCount = cpu_to_le16(params);
5538 pSMB->TotalParameterCount = pSMB->ParameterCount;
5539 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005540 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 parm_data->FileSize = cpu_to_le64(size);
5542 pSMB->ByteCount = cpu_to_le16(byte_count);
5543 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5544 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005545 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005546 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547
5548 cifs_buf_release(pSMB);
5549
5550 if (rc == -EAGAIN)
5551 goto SetEOFRetry;
5552
5553 return rc;
5554}
5555
5556int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005557CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5558 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559{
5560 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 struct file_end_of_file_info *parm_data;
5562 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 __u16 params, param_offset, offset, byte_count, count;
5564
Joe Perchesf96637b2013-05-04 22:12:25 -05005565 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5566 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005567 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5568
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 if (rc)
5570 return rc;
5571
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005572 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5573 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005574
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 params = 6;
5576 pSMB->MaxSetupCount = 0;
5577 pSMB->Reserved = 0;
5578 pSMB->Flags = 0;
5579 pSMB->Timeout = 0;
5580 pSMB->Reserved2 = 0;
5581 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5582 offset = param_offset + params;
5583
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 count = sizeof(struct file_end_of_file_info);
5585 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005586 /* BB find exact max SMB PDU from sess structure BB */
5587 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 pSMB->SetupCount = 1;
5589 pSMB->Reserved3 = 0;
5590 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5591 byte_count = 3 /* pad */ + params + count;
5592 pSMB->DataCount = cpu_to_le16(count);
5593 pSMB->ParameterCount = cpu_to_le16(params);
5594 pSMB->TotalDataCount = pSMB->DataCount;
5595 pSMB->TotalParameterCount = pSMB->ParameterCount;
5596 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5597 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005598 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5599 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 pSMB->DataOffset = cpu_to_le16(offset);
5601 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005602 pSMB->Fid = cfile->fid.netfid;
5603 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5605 pSMB->InformationLevel =
5606 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5607 else
5608 pSMB->InformationLevel =
5609 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005610 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5612 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005613 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 else
5615 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005616 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 }
5618 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005619 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005621 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005622 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005624 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5625 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 }
5627
Steve French50c2f752007-07-13 00:33:32 +00005628 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 since file handle passed in no longer valid */
5630
5631 return rc;
5632}
5633
Steve French50c2f752007-07-13 00:33:32 +00005634/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 an open handle, rather than by pathname - this is awkward due to
5636 potential access conflicts on the open, but it is unavoidable for these
5637 old servers since the only other choice is to go from 100 nanosecond DCE
5638 time and resort to the original setpathinfo level which takes the ancient
5639 DOS time format with 2 second granularity */
5640int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005641CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005642 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643{
5644 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 char *data_offset;
5646 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 __u16 params, param_offset, offset, byte_count, count;
5648
Joe Perchesf96637b2013-05-04 22:12:25 -05005649 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005650 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5651
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 if (rc)
5653 return rc;
5654
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005655 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5656 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005657
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 params = 6;
5659 pSMB->MaxSetupCount = 0;
5660 pSMB->Reserved = 0;
5661 pSMB->Flags = 0;
5662 pSMB->Timeout = 0;
5663 pSMB->Reserved2 = 0;
5664 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5665 offset = param_offset + params;
5666
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005667 data_offset = (char *)pSMB +
5668 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Steve French26f57362007-08-30 22:09:15 +00005670 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005672 /* BB find max SMB PDU from sess */
5673 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 pSMB->SetupCount = 1;
5675 pSMB->Reserved3 = 0;
5676 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5677 byte_count = 3 /* pad */ + params + count;
5678 pSMB->DataCount = cpu_to_le16(count);
5679 pSMB->ParameterCount = cpu_to_le16(params);
5680 pSMB->TotalDataCount = pSMB->DataCount;
5681 pSMB->TotalParameterCount = pSMB->ParameterCount;
5682 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5683 pSMB->DataOffset = cpu_to_le16(offset);
5684 pSMB->Fid = fid;
5685 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5686 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5687 else
5688 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5689 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005690 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005692 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005693 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005694 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005695 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005696 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5697 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
Steve French50c2f752007-07-13 00:33:32 +00005699 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 since file handle passed in no longer valid */
5701
5702 return rc;
5703}
5704
Jeff Layton6d22f092008-09-23 11:48:35 -04005705int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005706CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005707 bool delete_file, __u16 fid, __u32 pid_of_opener)
5708{
5709 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5710 char *data_offset;
5711 int rc = 0;
5712 __u16 params, param_offset, offset, byte_count, count;
5713
Joe Perchesf96637b2013-05-04 22:12:25 -05005714 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005715 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5716
5717 if (rc)
5718 return rc;
5719
5720 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5721 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5722
5723 params = 6;
5724 pSMB->MaxSetupCount = 0;
5725 pSMB->Reserved = 0;
5726 pSMB->Flags = 0;
5727 pSMB->Timeout = 0;
5728 pSMB->Reserved2 = 0;
5729 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5730 offset = param_offset + params;
5731
5732 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5733
5734 count = 1;
5735 pSMB->MaxParameterCount = cpu_to_le16(2);
5736 /* BB find max SMB PDU from sess */
5737 pSMB->MaxDataCount = cpu_to_le16(1000);
5738 pSMB->SetupCount = 1;
5739 pSMB->Reserved3 = 0;
5740 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5741 byte_count = 3 /* pad */ + params + count;
5742 pSMB->DataCount = cpu_to_le16(count);
5743 pSMB->ParameterCount = cpu_to_le16(params);
5744 pSMB->TotalDataCount = pSMB->DataCount;
5745 pSMB->TotalParameterCount = pSMB->ParameterCount;
5746 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5747 pSMB->DataOffset = cpu_to_le16(offset);
5748 pSMB->Fid = fid;
5749 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5750 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005751 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005752 pSMB->ByteCount = cpu_to_le16(byte_count);
5753 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005754 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005755 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005756 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005757 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005758
5759 return rc;
5760}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761
5762int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005763CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005764 const char *fileName, const FILE_BASIC_INFO *data,
5765 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766{
5767 TRANSACTION2_SPI_REQ *pSMB = NULL;
5768 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5769 int name_len;
5770 int rc = 0;
5771 int bytes_returned = 0;
5772 char *data_offset;
5773 __u16 params, param_offset, offset, byte_count, count;
5774
Joe Perchesf96637b2013-05-04 22:12:25 -05005775 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776
5777SetTimesRetry:
5778 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5779 (void **) &pSMBr);
5780 if (rc)
5781 return rc;
5782
5783 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5784 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005785 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5786 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 name_len++; /* trailing null */
5788 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005789 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 name_len = strnlen(fileName, PATH_MAX);
5791 name_len++; /* trailing null */
5792 strncpy(pSMB->FileName, fileName, name_len);
5793 }
5794
5795 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005796 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005798 /* BB find max SMB PDU from sess structure BB */
5799 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 pSMB->MaxSetupCount = 0;
5801 pSMB->Reserved = 0;
5802 pSMB->Flags = 0;
5803 pSMB->Timeout = 0;
5804 pSMB->Reserved2 = 0;
5805 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005806 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 offset = param_offset + params;
5808 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5809 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5810 pSMB->DataOffset = cpu_to_le16(offset);
5811 pSMB->SetupCount = 1;
5812 pSMB->Reserved3 = 0;
5813 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5814 byte_count = 3 /* pad */ + params + count;
5815
5816 pSMB->DataCount = cpu_to_le16(count);
5817 pSMB->ParameterCount = cpu_to_le16(params);
5818 pSMB->TotalDataCount = pSMB->DataCount;
5819 pSMB->TotalParameterCount = pSMB->ParameterCount;
5820 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5821 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5822 else
5823 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5824 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005825 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005826 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 pSMB->ByteCount = cpu_to_le16(byte_count);
5828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005830 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005831 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832
5833 cifs_buf_release(pSMB);
5834
5835 if (rc == -EAGAIN)
5836 goto SetTimesRetry;
5837
5838 return rc;
5839}
5840
5841/* Can not be used to set time stamps yet (due to old DOS time format) */
5842/* Can be used to set attributes */
5843#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5844 handling it anyway and NT4 was what we thought it would be needed for
5845 Do not delete it until we prove whether needed for Win9x though */
5846int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005847CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848 __u16 dos_attrs, const struct nls_table *nls_codepage)
5849{
5850 SETATTR_REQ *pSMB = NULL;
5851 SETATTR_RSP *pSMBr = NULL;
5852 int rc = 0;
5853 int bytes_returned;
5854 int name_len;
5855
Joe Perchesf96637b2013-05-04 22:12:25 -05005856 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
5858SetAttrLgcyRetry:
5859 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5860 (void **) &pSMBr);
5861 if (rc)
5862 return rc;
5863
5864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5865 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005866 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5867 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 name_len++; /* trailing null */
5869 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005870 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 name_len = strnlen(fileName, PATH_MAX);
5872 name_len++; /* trailing null */
5873 strncpy(pSMB->fileName, fileName, name_len);
5874 }
5875 pSMB->attr = cpu_to_le16(dos_attrs);
5876 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005877 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005881 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005882 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883
5884 cifs_buf_release(pSMB);
5885
5886 if (rc == -EAGAIN)
5887 goto SetAttrLgcyRetry;
5888
5889 return rc;
5890}
5891#endif /* temporarily unneeded SetAttr legacy function */
5892
Jeff Layton654cf142009-07-09 20:02:49 -04005893static void
5894cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5895 const struct cifs_unix_set_info_args *args)
5896{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005897 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005898 u64 mode = args->mode;
5899
Eric W. Biederman49418b22013-02-06 00:57:56 -08005900 if (uid_valid(args->uid))
5901 uid = from_kuid(&init_user_ns, args->uid);
5902 if (gid_valid(args->gid))
5903 gid = from_kgid(&init_user_ns, args->gid);
5904
Jeff Layton654cf142009-07-09 20:02:49 -04005905 /*
5906 * Samba server ignores set of file size to zero due to bugs in some
5907 * older clients, but we should be precise - we use SetFileSize to
5908 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005909 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005910 * zero instead of -1 here
5911 */
5912 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5913 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5914 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5915 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5916 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005917 data_offset->Uid = cpu_to_le64(uid);
5918 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005919 /* better to leave device as zero when it is */
5920 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5921 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5922 data_offset->Permissions = cpu_to_le64(mode);
5923
5924 if (S_ISREG(mode))
5925 data_offset->Type = cpu_to_le32(UNIX_FILE);
5926 else if (S_ISDIR(mode))
5927 data_offset->Type = cpu_to_le32(UNIX_DIR);
5928 else if (S_ISLNK(mode))
5929 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5930 else if (S_ISCHR(mode))
5931 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5932 else if (S_ISBLK(mode))
5933 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5934 else if (S_ISFIFO(mode))
5935 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5936 else if (S_ISSOCK(mode))
5937 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5938}
5939
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005941CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005942 const struct cifs_unix_set_info_args *args,
5943 u16 fid, u32 pid_of_opener)
5944{
5945 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005946 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005947 int rc = 0;
5948 u16 params, param_offset, offset, byte_count, count;
5949
Joe Perchesf96637b2013-05-04 22:12:25 -05005950 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005951 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5952
5953 if (rc)
5954 return rc;
5955
5956 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5957 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5958
5959 params = 6;
5960 pSMB->MaxSetupCount = 0;
5961 pSMB->Reserved = 0;
5962 pSMB->Flags = 0;
5963 pSMB->Timeout = 0;
5964 pSMB->Reserved2 = 0;
5965 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5966 offset = param_offset + params;
5967
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005968 data_offset = (char *)pSMB +
5969 offsetof(struct smb_hdr, Protocol) + offset;
5970
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005971 count = sizeof(FILE_UNIX_BASIC_INFO);
5972
5973 pSMB->MaxParameterCount = cpu_to_le16(2);
5974 /* BB find max SMB PDU from sess */
5975 pSMB->MaxDataCount = cpu_to_le16(1000);
5976 pSMB->SetupCount = 1;
5977 pSMB->Reserved3 = 0;
5978 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5979 byte_count = 3 /* pad */ + params + count;
5980 pSMB->DataCount = cpu_to_le16(count);
5981 pSMB->ParameterCount = cpu_to_le16(params);
5982 pSMB->TotalDataCount = pSMB->DataCount;
5983 pSMB->TotalParameterCount = pSMB->ParameterCount;
5984 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5985 pSMB->DataOffset = cpu_to_le16(offset);
5986 pSMB->Fid = fid;
5987 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5988 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005989 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005990 pSMB->ByteCount = cpu_to_le16(byte_count);
5991
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005992 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005993
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005994 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005995 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005996 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005997 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5998 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005999
6000 /* Note: On -EAGAIN error only caller can retry on handle based calls
6001 since file handle passed in no longer valid */
6002
6003 return rc;
6004}
6005
6006int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006007CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006008 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006009 const struct cifs_unix_set_info_args *args,
6010 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011{
6012 TRANSACTION2_SPI_REQ *pSMB = NULL;
6013 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6014 int name_len;
6015 int rc = 0;
6016 int bytes_returned = 0;
6017 FILE_UNIX_BASIC_INFO *data_offset;
6018 __u16 params, param_offset, offset, count, byte_count;
6019
Joe Perchesf96637b2013-05-04 22:12:25 -05006020 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021setPermsRetry:
6022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6023 (void **) &pSMBr);
6024 if (rc)
6025 return rc;
6026
6027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6028 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006029 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006030 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 name_len++; /* trailing null */
6032 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006033 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006034 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006036 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037 }
6038
6039 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006040 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006042 /* BB find max SMB PDU from sess structure BB */
6043 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 pSMB->MaxSetupCount = 0;
6045 pSMB->Reserved = 0;
6046 pSMB->Flags = 0;
6047 pSMB->Timeout = 0;
6048 pSMB->Reserved2 = 0;
6049 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006050 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051 offset = param_offset + params;
6052 data_offset =
6053 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6054 offset);
6055 memset(data_offset, 0, count);
6056 pSMB->DataOffset = cpu_to_le16(offset);
6057 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6058 pSMB->SetupCount = 1;
6059 pSMB->Reserved3 = 0;
6060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6061 byte_count = 3 /* pad */ + params + count;
6062 pSMB->ParameterCount = cpu_to_le16(params);
6063 pSMB->DataCount = cpu_to_le16(count);
6064 pSMB->TotalParameterCount = pSMB->ParameterCount;
6065 pSMB->TotalDataCount = pSMB->DataCount;
6066 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6067 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006068 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006069
Jeff Layton654cf142009-07-09 20:02:49 -04006070 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071
6072 pSMB->ByteCount = cpu_to_le16(byte_count);
6073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006075 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006076 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077
Steve French0d817bc2008-05-22 02:02:03 +00006078 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079 if (rc == -EAGAIN)
6080 goto setPermsRetry;
6081 return rc;
6082}
6083
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006085/*
6086 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6087 * function used by listxattr and getxattr type calls. When ea_name is set,
6088 * it looks for that attribute name and stuffs that value into the EAData
6089 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6090 * buffer. In both cases, the return value is either the length of the
6091 * resulting data or a negative error code. If EAData is a NULL pointer then
6092 * the data isn't copied to it, but the length is returned.
6093 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006095CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006096 const unsigned char *searchName, const unsigned char *ea_name,
6097 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006098 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099{
6100 /* BB assumes one setup word */
6101 TRANSACTION2_QPI_REQ *pSMB = NULL;
6102 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006103 int remap = cifs_remap(cifs_sb);
6104 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 int rc = 0;
6106 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006107 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006108 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006109 struct fea *temp_fea;
6110 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006111 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006112 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006113 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114
Joe Perchesf96637b2013-05-04 22:12:25 -05006115 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116QAllEAsRetry:
6117 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6118 (void **) &pSMBr);
6119 if (rc)
6120 return rc;
6121
6122 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006123 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006124 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6125 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006126 list_len++; /* trailing null */
6127 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006129 list_len = strnlen(searchName, PATH_MAX);
6130 list_len++; /* trailing null */
6131 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 }
6133
Jeff Layton6e462b92010-02-10 16:18:26 -05006134 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 pSMB->TotalDataCount = 0;
6136 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006137 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006138 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139 pSMB->MaxSetupCount = 0;
6140 pSMB->Reserved = 0;
6141 pSMB->Flags = 0;
6142 pSMB->Timeout = 0;
6143 pSMB->Reserved2 = 0;
6144 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006145 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 pSMB->DataCount = 0;
6147 pSMB->DataOffset = 0;
6148 pSMB->SetupCount = 1;
6149 pSMB->Reserved3 = 0;
6150 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6151 byte_count = params + 1 /* pad */ ;
6152 pSMB->TotalParameterCount = cpu_to_le16(params);
6153 pSMB->ParameterCount = pSMB->TotalParameterCount;
6154 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6155 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006156 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 pSMB->ByteCount = cpu_to_le16(byte_count);
6158
6159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6161 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006162 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006163 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006165
6166
6167 /* BB also check enough total bytes returned */
6168 /* BB we need to improve the validity checking
6169 of these trans2 responses */
6170
6171 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006172 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006173 rc = -EIO; /* bad smb */
6174 goto QAllEAsOut;
6175 }
6176
6177 /* check that length of list is not more than bcc */
6178 /* check that each entry does not go beyond length
6179 of list */
6180 /* check that each element of each entry does not
6181 go beyond end of list */
6182 /* validate_trans2_offsets() */
6183 /* BB check if start of smb + data_offset > &bcc+ bcc */
6184
6185 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6186 ea_response_data = (struct fealist *)
6187 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6188
Jeff Layton6e462b92010-02-10 16:18:26 -05006189 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006190 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006191 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006192 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006193 /* didn't find the named attribute */
6194 if (ea_name)
6195 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006196 goto QAllEAsOut;
6197 }
6198
Jeff Layton0cd126b2010-02-10 16:18:26 -05006199 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006200 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006201 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006202 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006203 rc = -EIO;
6204 goto QAllEAsOut;
6205 }
6206
Jeff Laytonf0d38682010-02-10 16:18:26 -05006207 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006208 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006209 temp_fea = ea_response_data->list;
6210 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006211 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006212 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006213 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006214
Jeff Layton6e462b92010-02-10 16:18:26 -05006215 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006216 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006217 /* make sure we can read name_len and value_len */
6218 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006219 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006220 rc = -EIO;
6221 goto QAllEAsOut;
6222 }
6223
6224 name_len = temp_fea->name_len;
6225 value_len = le16_to_cpu(temp_fea->value_len);
6226 list_len -= name_len + 1 + value_len;
6227 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006228 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006229 rc = -EIO;
6230 goto QAllEAsOut;
6231 }
6232
Jeff Layton31c05192010-02-10 16:18:26 -05006233 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006234 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006235 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006236 temp_ptr += name_len + 1;
6237 rc = value_len;
6238 if (buf_size == 0)
6239 goto QAllEAsOut;
6240 if ((size_t)value_len > buf_size) {
6241 rc = -ERANGE;
6242 goto QAllEAsOut;
6243 }
6244 memcpy(EAData, temp_ptr, value_len);
6245 goto QAllEAsOut;
6246 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006247 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006248 /* account for prefix user. and trailing null */
6249 rc += (5 + 1 + name_len);
6250 if (rc < (int) buf_size) {
6251 memcpy(EAData, "user.", 5);
6252 EAData += 5;
6253 memcpy(EAData, temp_ptr, name_len);
6254 EAData += name_len;
6255 /* null terminate name */
6256 *EAData = 0;
6257 ++EAData;
6258 } else if (buf_size == 0) {
6259 /* skip copy - calc size only */
6260 } else {
6261 /* stop before overrun buffer */
6262 rc = -ERANGE;
6263 break;
6264 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006265 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006266 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006267 temp_fea = (struct fea *)temp_ptr;
6268 }
6269
Jeff Layton31c05192010-02-10 16:18:26 -05006270 /* didn't find the named attribute */
6271 if (ea_name)
6272 rc = -ENODATA;
6273
Jeff Laytonf0d38682010-02-10 16:18:26 -05006274QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006275 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 if (rc == -EAGAIN)
6277 goto QAllEAsRetry;
6278
6279 return (ssize_t)rc;
6280}
6281
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006283CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6284 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006285 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006286 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006287{
6288 struct smb_com_transaction2_spi_req *pSMB = NULL;
6289 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6290 struct fealist *parm_data;
6291 int name_len;
6292 int rc = 0;
6293 int bytes_returned = 0;
6294 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006295 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296
Joe Perchesf96637b2013-05-04 22:12:25 -05006297 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298SetEARetry:
6299 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6300 (void **) &pSMBr);
6301 if (rc)
6302 return rc;
6303
6304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6305 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006306 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6307 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 name_len++; /* trailing null */
6309 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006310 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311 name_len = strnlen(fileName, PATH_MAX);
6312 name_len++; /* trailing null */
6313 strncpy(pSMB->FileName, fileName, name_len);
6314 }
6315
6316 params = 6 + name_len;
6317
6318 /* done calculating parms using name_len of file name,
6319 now use name_len to calculate length of ea name
6320 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006321 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322 name_len = 0;
6323 else
Steve French50c2f752007-07-13 00:33:32 +00006324 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006326 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006328 /* BB find max SMB PDU from sess */
6329 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 pSMB->MaxSetupCount = 0;
6331 pSMB->Reserved = 0;
6332 pSMB->Flags = 0;
6333 pSMB->Timeout = 0;
6334 pSMB->Reserved2 = 0;
6335 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006336 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 offset = param_offset + params;
6338 pSMB->InformationLevel =
6339 cpu_to_le16(SMB_SET_FILE_EA);
6340
6341 parm_data =
6342 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6343 offset);
6344 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6345 pSMB->DataOffset = cpu_to_le16(offset);
6346 pSMB->SetupCount = 1;
6347 pSMB->Reserved3 = 0;
6348 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6349 byte_count = 3 /* pad */ + params + count;
6350 pSMB->DataCount = cpu_to_le16(count);
6351 parm_data->list_len = cpu_to_le32(count);
6352 parm_data->list[0].EA_flags = 0;
6353 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006354 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006356 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006357 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 parm_data->list[0].name[name_len] = 0;
6359 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6360 /* caller ensures that ea_value_len is less than 64K but
6361 we need to ensure that it fits within the smb */
6362
Steve French50c2f752007-07-13 00:33:32 +00006363 /*BB add length check to see if it would fit in
6364 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006365 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6366 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006367 memcpy(parm_data->list[0].name+name_len+1,
6368 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369
6370 pSMB->TotalDataCount = pSMB->DataCount;
6371 pSMB->ParameterCount = cpu_to_le16(params);
6372 pSMB->TotalParameterCount = pSMB->ParameterCount;
6373 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006374 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 pSMB->ByteCount = cpu_to_le16(byte_count);
6376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006378 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006379 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380
6381 cifs_buf_release(pSMB);
6382
6383 if (rc == -EAGAIN)
6384 goto SetEARetry;
6385
6386 return rc;
6387}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388#endif
Steve French0eff0e22011-02-24 05:39:23 +00006389
6390#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6391/*
6392 * Years ago the kernel added a "dnotify" function for Samba server,
6393 * to allow network clients (such as Windows) to display updated
6394 * lists of files in directory listings automatically when
6395 * files are added by one user when another user has the
6396 * same directory open on their desktop. The Linux cifs kernel
6397 * client hooked into the kernel side of this interface for
6398 * the same reason, but ironically when the VFS moved from
6399 * "dnotify" to "inotify" it became harder to plug in Linux
6400 * network file system clients (the most obvious use case
6401 * for notify interfaces is when multiple users can update
6402 * the contents of the same directory - exactly what network
6403 * file systems can do) although the server (Samba) could
6404 * still use it. For the short term we leave the worker
6405 * function ifdeffed out (below) until inotify is fixed
6406 * in the VFS to make it easier to plug in network file
6407 * system clients. If inotify turns out to be permanently
6408 * incompatible for network fs clients, we could instead simply
6409 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6410 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006411int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006412 const int notify_subdirs, const __u16 netfid,
6413 __u32 filter, struct file *pfile, int multishot,
6414 const struct nls_table *nls_codepage)
6415{
6416 int rc = 0;
6417 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6418 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6419 struct dir_notify_req *dnotify_req;
6420 int bytes_returned;
6421
Joe Perchesf96637b2013-05-04 22:12:25 -05006422 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006423 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6424 (void **) &pSMBr);
6425 if (rc)
6426 return rc;
6427
6428 pSMB->TotalParameterCount = 0 ;
6429 pSMB->TotalDataCount = 0;
6430 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006431 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006432 pSMB->MaxSetupCount = 4;
6433 pSMB->Reserved = 0;
6434 pSMB->ParameterOffset = 0;
6435 pSMB->DataCount = 0;
6436 pSMB->DataOffset = 0;
6437 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6438 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6439 pSMB->ParameterCount = pSMB->TotalParameterCount;
6440 if (notify_subdirs)
6441 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6442 pSMB->Reserved2 = 0;
6443 pSMB->CompletionFilter = cpu_to_le32(filter);
6444 pSMB->Fid = netfid; /* file handle always le */
6445 pSMB->ByteCount = 0;
6446
6447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6448 (struct smb_hdr *)pSMBr, &bytes_returned,
6449 CIFS_ASYNC_OP);
6450 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006451 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006452 } else {
6453 /* Add file to outstanding requests */
6454 /* BB change to kmem cache alloc */
6455 dnotify_req = kmalloc(
6456 sizeof(struct dir_notify_req),
6457 GFP_KERNEL);
6458 if (dnotify_req) {
6459 dnotify_req->Pid = pSMB->hdr.Pid;
6460 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6461 dnotify_req->Mid = pSMB->hdr.Mid;
6462 dnotify_req->Tid = pSMB->hdr.Tid;
6463 dnotify_req->Uid = pSMB->hdr.Uid;
6464 dnotify_req->netfid = netfid;
6465 dnotify_req->pfile = pfile;
6466 dnotify_req->filter = filter;
6467 dnotify_req->multishot = multishot;
6468 spin_lock(&GlobalMid_Lock);
6469 list_add_tail(&dnotify_req->lhead,
6470 &GlobalDnotifyReqList);
6471 spin_unlock(&GlobalMid_Lock);
6472 } else
6473 rc = -ENOMEM;
6474 }
6475 cifs_buf_release(pSMB);
6476 return rc;
6477}
6478#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */