blob: e3fed9249a04f09929e772c0f4c9b0955263b13b [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 Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500101 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Steve French3afca262016-09-22 18:58:16 -0500107 spin_unlock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500142 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500166 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 rc = cifs_setup_session(0, ses, nls_codepage);
184
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 goto out;
189 }
190
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400191 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500194 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
Jeff Layton9162ab22009-09-03 12:07:17 -0400199 atomic_inc(&tconInfoReconnectCount);
200
201 /* tell server Unix caps we support */
202 if (ses->capabilities & CAP_UNIX)
203 reset_cifs_unix_caps(0, tcon, NULL, NULL);
204
205 /*
206 * Removed call to reopen open files here. It is safer (and faster) to
207 * reopen files one at a time as needed in read and write.
208 *
209 * FIXME: what about file locks? don't we need to reclaim them ASAP?
210 */
211
212out:
213 /*
214 * Check if handle based operation so we know whether we can continue
215 * or not without returning to caller to reset file handle
216 */
217 switch (smb_command) {
218 case SMB_COM_READ_ANDX:
219 case SMB_COM_WRITE_ANDX:
220 case SMB_COM_CLOSE:
221 case SMB_COM_FIND_CLOSE2:
222 case SMB_COM_LOCKING_ANDX:
223 rc = -EAGAIN;
224 }
225
226 unload_nls(nls_codepage);
227 return rc;
228}
229
Steve Frenchad7a2922008-02-07 23:25:02 +0000230/* Allocate and return pointer to an SMB request buffer, and set basic
231 SMB information in the SMB header. If the return code is zero, this
232 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int
Steve French96daf2b2011-05-27 04:34:02 +0000234small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000235 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Jeff Laytonf5695992010-09-29 15:27:08 -0400237 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Jeff Layton9162ab22009-09-03 12:07:17 -0400239 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000240 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 return rc;
242
243 *request_buf = cifs_small_buf_get();
244 if (*request_buf == NULL) {
245 /* BB should we add a retry in here if not a writepage? */
246 return -ENOMEM;
247 }
248
Steve French63135e02007-07-17 17:34:02 +0000249 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000250 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Steve French790fe572007-07-07 19:25:05 +0000252 if (tcon != NULL)
253 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700254
Jeff Laytonf5695992010-09-29 15:27:08 -0400255 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000256}
257
Steve French12b3b8f2006-02-09 21:12:47 +0000258int
Steve French50c2f752007-07-13 00:33:32 +0000259small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000260 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000261{
262 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000263 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000264
Steve French5815449d2006-02-14 01:36:20 +0000265 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000266 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000267 return rc;
268
Steve French04fdabe2006-02-10 05:52:50 +0000269 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400270 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000271 if (ses->capabilities & CAP_UNICODE)
272 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000273 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000274 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
275
276 /* uid, tid can stay at zero as set in header assemble */
277
Steve French50c2f752007-07-13 00:33:32 +0000278 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000279 this function is used after 1st of session setup requests */
280
281 return rc;
282}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284/* If the return code is zero, this function must fill in request_buf pointer */
285static int
Steve French96daf2b2011-05-27 04:34:02 +0000286__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400287 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 *request_buf = cifs_buf_get();
290 if (*request_buf == NULL) {
291 /* BB should we add a retry in here if not a writepage? */
292 return -ENOMEM;
293 }
294 /* Although the original thought was we needed the response buf for */
295 /* potential retries of smb operations it turns out we can determine */
296 /* from the mid flags when the request buffer can be resent without */
297 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000298 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000299 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000302 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Steve French790fe572007-07-07 19:25:05 +0000304 if (tcon != NULL)
305 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700306
Jeff Laytonf5695992010-09-29 15:27:08 -0400307 return 0;
308}
309
310/* If the return code is zero, this function must fill in request_buf pointer */
311static int
Steve French96daf2b2011-05-27 04:34:02 +0000312smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400313 void **request_buf, void **response_buf)
314{
315 int rc;
316
317 rc = cifs_reconnect_tcon(tcon, smb_command);
318 if (rc)
319 return rc;
320
321 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
322}
323
324static int
Steve French96daf2b2011-05-27 04:34:02 +0000325smb_init_no_reconnect(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 if (tcon->ses->need_reconnect || tcon->need_reconnect)
329 return -EHOSTDOWN;
330
331 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Steve French50c2f752007-07-13 00:33:32 +0000334static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Jeff Layton12df83c2011-01-20 13:36:51 -0500336 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Jeff Layton12df83c2011-01-20 13:36:51 -0500338 /* check for plausible wct */
339 if (pSMB->hdr.WordCount < 10)
340 goto vt2_err;
341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500343 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
344 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
345 goto vt2_err;
346
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
348 if (total_size >= 512)
349 goto vt2_err;
350
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400351 /* check that bcc is at least as big as parms + data, and that it is
352 * less than negotiated smb buffer
353 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500354 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
355 if (total_size > get_bcc(&pSMB->hdr) ||
356 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
357 goto vt2_err;
358
359 return 0;
360vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000361 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500363 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
Jeff Layton690c5222011-01-20 13:36:51 -0500365
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400366static int
Jeff Layton3f618222013-06-12 19:52:14 -0500367decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400368{
369 int rc = 0;
370 u16 count;
371 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500372 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400373
374 count = get_bcc(&pSMBr->hdr);
375 if (count < SMB1_CLIENT_GUID_SIZE)
376 return -EIO;
377
378 spin_lock(&cifs_tcp_ses_lock);
379 if (server->srv_count > 1) {
380 spin_unlock(&cifs_tcp_ses_lock);
381 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
382 cifs_dbg(FYI, "server UID changed\n");
383 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
384 }
385 } else {
386 spin_unlock(&cifs_tcp_ses_lock);
387 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
388 }
389
390 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500391 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400392 } else {
393 count -= SMB1_CLIENT_GUID_SIZE;
394 rc = decode_negTokenInit(
395 pSMBr->u.extended_response.SecurityBlob, count, server);
396 if (rc != 1)
397 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400398 }
399
400 return 0;
401}
402
Jeff Layton9ddec562013-05-26 07:00:58 -0400403int
Jeff Layton38d77c52013-05-26 07:01:00 -0400404cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400405{
Jeff Layton50285882013-06-27 12:45:00 -0400406 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
407 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400408 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
409
410 /*
411 * Is signing required by mnt options? If not then check
412 * global_secflags to see if it is there.
413 */
414 if (!mnt_sign_required)
415 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
416 CIFSSEC_MUST_SIGN);
417
418 /*
419 * If signing is required then it's automatically enabled too,
420 * otherwise, check to see if the secflags allow it.
421 */
422 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
423 (global_secflags & CIFSSEC_MAY_SIGN);
424
425 /* If server requires signing, does client allow it? */
426 if (srv_sign_required) {
427 if (!mnt_sign_enabled) {
428 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
429 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400430 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400431 server->sign = true;
432 }
433
434 /* If client requires signing, does server allow it? */
435 if (mnt_sign_required) {
436 if (!srv_sign_enabled) {
437 cifs_dbg(VFS, "Server does not support signing!");
438 return -ENOTSUPP;
439 }
440 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400441 }
442
443 return 0;
444}
445
Jeff Layton2190eca2013-05-26 07:00:57 -0400446#ifdef CONFIG_CIFS_WEAK_PW_HASH
447static int
Jeff Layton3f618222013-06-12 19:52:14 -0500448decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400449{
450 __s16 tmp;
451 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
452
453 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
454 return -EOPNOTSUPP;
455
Jeff Layton2190eca2013-05-26 07:00:57 -0400456 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
457 server->maxReq = min_t(unsigned int,
458 le16_to_cpu(rsp->MaxMpxCount),
459 cifs_max_pending);
460 set_credits(server, server->maxReq);
461 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400462 /* even though we do not use raw we might as well set this
463 accurately, in case we ever find a need for it */
464 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
465 server->max_rw = 0xFF00;
466 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
467 } else {
468 server->max_rw = 0;/* do not need to use raw anyway */
469 server->capabilities = CAP_MPX_MODE;
470 }
471 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
472 if (tmp == -1) {
473 /* OS/2 often does not set timezone therefore
474 * we must use server time to calc time zone.
475 * Could deviate slightly from the right zone.
476 * Smallest defined timezone difference is 15 minutes
477 * (i.e. Nepal). Rounding up/down is done to match
478 * this requirement.
479 */
480 int val, seconds, remain, result;
481 struct timespec ts, utc;
482 utc = CURRENT_TIME;
483 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
484 rsp->SrvTime.Time, 0);
485 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
486 (int)ts.tv_sec, (int)utc.tv_sec,
487 (int)(utc.tv_sec - ts.tv_sec));
488 val = (int)(utc.tv_sec - ts.tv_sec);
489 seconds = abs(val);
490 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
491 remain = seconds % MIN_TZ_ADJ;
492 if (remain >= (MIN_TZ_ADJ / 2))
493 result += MIN_TZ_ADJ;
494 if (val < 0)
495 result = -result;
496 server->timeAdj = result;
497 } else {
498 server->timeAdj = (int)tmp;
499 server->timeAdj *= 60; /* also in seconds */
500 }
501 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
502
503
504 /* BB get server time for time conversions and add
505 code to use it and timezone since this is not UTC */
506
507 if (rsp->EncryptionKeyLength ==
508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
509 memcpy(server->cryptkey, rsp->EncryptionKey,
510 CIFS_CRYPTO_KEY_SIZE);
511 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
512 return -EIO; /* need cryptkey unless plain text */
513 }
514
515 cifs_dbg(FYI, "LANMAN negotiated\n");
516 return 0;
517}
518#else
519static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500520decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400521{
522 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
523 return -EOPNOTSUPP;
524}
525#endif
526
Jeff Layton91934002013-05-26 07:00:58 -0400527static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500528should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400529{
Jeff Layton3f618222013-06-12 19:52:14 -0500530 switch (sectype) {
531 case RawNTLMSSP:
532 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400533 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500534 case Unspecified:
535 if (global_secflags &
536 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
537 return true;
538 /* Fallthrough */
539 default:
540 return false;
541 }
Jeff Layton91934002013-05-26 07:00:58 -0400542}
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400545CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 NEGOTIATE_REQ *pSMB;
548 NEGOTIATE_RSP *pSMBr;
549 int rc = 0;
550 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000551 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400552 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 u16 count;
554
Jeff Layton3534b852013-05-24 07:41:01 -0400555 if (!server) {
556 WARN(1, "%s: server is NULL!\n", __func__);
557 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 }
Jeff Layton3534b852013-05-24 07:41:01 -0400559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
561 (void **) &pSMB, (void **) &pSMBr);
562 if (rc)
563 return rc;
Steve French750d1152006-06-27 06:28:30 +0000564
Pavel Shilovsky88257362012-05-23 14:01:59 +0400565 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000566 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000567
Jeff Layton3f618222013-06-12 19:52:14 -0500568 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400569 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000570 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
571 }
Steve French50c2f752007-07-13 00:33:32 +0000572
Steve French39798772006-05-31 22:40:51 +0000573 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000574 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000575 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
576 count += strlen(protocols[i].name) + 1;
577 /* null at end of source and target buffers anyway */
578 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000579 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 pSMB->ByteCount = cpu_to_le16(count);
581
582 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
583 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000584 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000585 goto neg_err_exit;
586
Jeff Layton9bf67e52010-04-24 07:57:46 -0400587 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500588 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000589 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400590 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000591 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000592 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000593 could not negotiate a common dialect */
594 rc = -EOPNOTSUPP;
595 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000596 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400597 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500598 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400599 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000600 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000601 /* unknown wct */
602 rc = -EOPNOTSUPP;
603 goto neg_err_exit;
604 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400605 /* else wct == 17, NTLM or better */
606
Steve French96daf2b2011-05-27 04:34:02 +0000607 server->sec_mode = pSMBr->SecurityMode;
608 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500609 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000610
Steve French254e55e2006-06-04 05:53:15 +0000611 /* one byte, so no need to convert this or EncryptionKeyLen from
612 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300613 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
614 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400615 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000616 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400617 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000618 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500619 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000620 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000621 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
622 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400623
Jeff Laytone598d1d82013-05-26 07:00:59 -0400624 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
625 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500626 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000627 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100628 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
629 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400630 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500631 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400632 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000633 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400634 } else {
635 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000636 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400637 }
Steve French254e55e2006-06-04 05:53:15 +0000638
639signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400640 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400641 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000642neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700643 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000644
Joe Perchesf96637b2013-05-04 22:12:25 -0500645 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 return rc;
647}
648
649int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400650CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651{
652 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Joe Perchesf96637b2013-05-04 22:12:25 -0500655 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500656
657 /* BB: do we need to check this? These should never be NULL. */
658 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
659 return -EIO;
660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500662 * No need to return error on this operation if tid invalidated and
663 * closed on server already e.g. due to tcp session crashing. Also,
664 * the tcon is no longer on the list, so no need to take lock before
665 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 */
Steve French268875b2009-06-25 00:29:21 +0000667 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000668 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Steve French50c2f752007-07-13 00:33:32 +0000670 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700671 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500672 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return rc;
Steve French133672e2007-11-13 22:41:37 +0000674
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400675 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500677 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Steve French50c2f752007-07-13 00:33:32 +0000679 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500680 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (rc == -EAGAIN)
682 rc = 0;
683
684 return rc;
685}
686
Jeff Layton766fdbb2011-01-11 07:24:21 -0500687/*
688 * This is a no-op for now. We're not really interested in the reply, but
689 * rather in the fact that the server sent one and that server->lstrp
690 * gets updated.
691 *
692 * FIXME: maybe we should consider checking that the reply matches request?
693 */
694static void
695cifs_echo_callback(struct mid_q_entry *mid)
696{
697 struct TCP_Server_Info *server = mid->callback_data;
698
Christopher Oo5fb4e282015-06-25 16:10:48 -0700699 mutex_lock(&server->srv_mutex);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500700 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -0700701 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400702 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500703}
704
705int
706CIFSSMBEcho(struct TCP_Server_Info *server)
707{
708 ECHO_REQ *smb;
709 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400710 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700711 struct smb_rqst rqst = { .rq_iov = &iov,
712 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500713
Joe Perchesf96637b2013-05-04 22:12:25 -0500714 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500715
716 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
717 if (rc)
718 return rc;
719
720 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000721 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500722 smb->hdr.WordCount = 1;
723 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400724 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000726 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400727 iov.iov_base = smb;
728 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500729
Jeff Laytonfec344e2012-09-18 16:20:35 -0700730 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400731 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500732 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500733 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500734
735 cifs_small_buf_release(smb);
736
737 return rc;
738}
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400741CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 LOGOFF_ANDX_REQ *pSMB;
744 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Joe Perchesf96637b2013-05-04 22:12:25 -0500746 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500747
748 /*
749 * BB: do we need to check validity of ses and server? They should
750 * always be valid since we have an active reference. If not, that
751 * should probably be a BUG()
752 */
753 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 return -EIO;
755
Steve Frenchd7b619c2010-02-25 05:36:46 +0000756 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000757 if (ses->need_reconnect)
758 goto session_already_dead; /* no need to send SMBlogoff if uid
759 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
761 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000762 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return rc;
764 }
765
Pavel Shilovsky88257362012-05-23 14:01:59 +0400766 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700767
Jeff Layton38d77c52013-05-26 07:01:00 -0400768 if (ses->server->sign)
769 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 pSMB->hdr.Uid = ses->Suid;
772
773 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400774 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000775session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000776 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000779 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 error */
781 if (rc == -EAGAIN)
782 rc = 0;
783 return rc;
784}
785
786int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400787CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
788 const char *fileName, __u16 type,
789 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000790{
791 TRANSACTION2_SPI_REQ *pSMB = NULL;
792 TRANSACTION2_SPI_RSP *pSMBr = NULL;
793 struct unlink_psx_rq *pRqD;
794 int name_len;
795 int rc = 0;
796 int bytes_returned = 0;
797 __u16 params, param_offset, offset, byte_count;
798
Joe Perchesf96637b2013-05-04 22:12:25 -0500799 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000800PsxDelete:
801 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
802 (void **) &pSMBr);
803 if (rc)
804 return rc;
805
806 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
807 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600808 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
809 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000810 name_len++; /* trailing null */
811 name_len *= 2;
812 } else { /* BB add path length overrun check */
813 name_len = strnlen(fileName, PATH_MAX);
814 name_len++; /* trailing null */
815 strncpy(pSMB->FileName, fileName, name_len);
816 }
817
818 params = 6 + name_len;
819 pSMB->MaxParameterCount = cpu_to_le16(2);
820 pSMB->MaxDataCount = 0; /* BB double check this with jra */
821 pSMB->MaxSetupCount = 0;
822 pSMB->Reserved = 0;
823 pSMB->Flags = 0;
824 pSMB->Timeout = 0;
825 pSMB->Reserved2 = 0;
826 param_offset = offsetof(struct smb_com_transaction2_spi_req,
827 InformationLevel) - 4;
828 offset = param_offset + params;
829
830 /* Setup pointer to Request Data (inode type) */
831 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
832 pRqD->type = cpu_to_le16(type);
833 pSMB->ParameterOffset = cpu_to_le16(param_offset);
834 pSMB->DataOffset = cpu_to_le16(offset);
835 pSMB->SetupCount = 1;
836 pSMB->Reserved3 = 0;
837 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
838 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
839
840 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
841 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
842 pSMB->ParameterCount = cpu_to_le16(params);
843 pSMB->TotalParameterCount = pSMB->ParameterCount;
844 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
845 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000846 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000847 pSMB->ByteCount = cpu_to_le16(byte_count);
848 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
849 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000850 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500851 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000852 cifs_buf_release(pSMB);
853
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400854 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000855
856 if (rc == -EAGAIN)
857 goto PsxDelete;
858
859 return rc;
860}
861
862int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700863CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
864 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 DELETE_FILE_REQ *pSMB = NULL;
867 DELETE_FILE_RSP *pSMBr = NULL;
868 int rc = 0;
869 int bytes_returned;
870 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500871 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873DelFileRetry:
874 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
875 (void **) &pSMBr);
876 if (rc)
877 return rc;
878
879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700880 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
881 PATH_MAX, cifs_sb->local_nls,
882 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 name_len++; /* trailing null */
884 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700885 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700886 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700888 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 }
890 pSMB->SearchAttributes =
891 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
892 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000893 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 pSMB->ByteCount = cpu_to_le16(name_len + 1);
895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400897 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000898 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500899 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 cifs_buf_release(pSMB);
902 if (rc == -EAGAIN)
903 goto DelFileRetry;
904
905 return rc;
906}
907
908int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400909CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
910 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 DELETE_DIRECTORY_REQ *pSMB = NULL;
913 DELETE_DIRECTORY_RSP *pSMBr = NULL;
914 int rc = 0;
915 int bytes_returned;
916 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500917 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Joe Perchesf96637b2013-05-04 22:12:25 -0500919 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920RmDirRetry:
921 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
922 (void **) &pSMBr);
923 if (rc)
924 return rc;
925
926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400927 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
928 PATH_MAX, cifs_sb->local_nls,
929 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 name_len++; /* trailing null */
931 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700932 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400933 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400935 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 }
937
938 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000939 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 pSMB->ByteCount = cpu_to_le16(name_len + 1);
941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400943 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000944 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500945 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 cifs_buf_release(pSMB);
948 if (rc == -EAGAIN)
949 goto RmDirRetry;
950 return rc;
951}
952
953int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300954CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
955 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956{
957 int rc = 0;
958 CREATE_DIRECTORY_REQ *pSMB = NULL;
959 CREATE_DIRECTORY_RSP *pSMBr = NULL;
960 int bytes_returned;
961 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500962 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Joe Perchesf96637b2013-05-04 22:12:25 -0500964 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965MkDirRetry:
966 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
967 (void **) &pSMBr);
968 if (rc)
969 return rc;
970
971 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600972 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300973 PATH_MAX, cifs_sb->local_nls,
974 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 name_len++; /* trailing null */
976 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700977 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 name_len = strnlen(name, PATH_MAX);
979 name_len++; /* trailing null */
980 strncpy(pSMB->DirName, name, name_len);
981 }
982
983 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000984 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 pSMB->ByteCount = cpu_to_le16(name_len + 1);
986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400988 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000989 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500990 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 cifs_buf_release(pSMB);
993 if (rc == -EAGAIN)
994 goto MkDirRetry;
995 return rc;
996}
997
Steve French2dd29d32007-04-23 22:07:35 +0000998int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400999CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1000 __u32 posix_flags, __u64 mode, __u16 *netfid,
1001 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1002 const char *name, const struct nls_table *nls_codepage,
1003 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001004{
1005 TRANSACTION2_SPI_REQ *pSMB = NULL;
1006 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1007 int name_len;
1008 int rc = 0;
1009 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001010 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 OPEN_PSX_REQ *pdata;
1012 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001013
Joe Perchesf96637b2013-05-04 22:12:25 -05001014 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001015PsxCreat:
1016 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1017 (void **) &pSMBr);
1018 if (rc)
1019 return rc;
1020
1021 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1022 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001023 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1024 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001025 name_len++; /* trailing null */
1026 name_len *= 2;
1027 } else { /* BB improve the check for buffer overruns BB */
1028 name_len = strnlen(name, PATH_MAX);
1029 name_len++; /* trailing null */
1030 strncpy(pSMB->FileName, name, name_len);
1031 }
1032
1033 params = 6 + name_len;
1034 count = sizeof(OPEN_PSX_REQ);
1035 pSMB->MaxParameterCount = cpu_to_le16(2);
1036 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1037 pSMB->MaxSetupCount = 0;
1038 pSMB->Reserved = 0;
1039 pSMB->Flags = 0;
1040 pSMB->Timeout = 0;
1041 pSMB->Reserved2 = 0;
1042 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001043 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001044 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001045 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001046 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001047 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001048 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001049 pdata->OpenFlags = cpu_to_le32(*pOplock);
1050 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1051 pSMB->DataOffset = cpu_to_le16(offset);
1052 pSMB->SetupCount = 1;
1053 pSMB->Reserved3 = 0;
1054 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1055 byte_count = 3 /* pad */ + params + count;
1056
1057 pSMB->DataCount = cpu_to_le16(count);
1058 pSMB->ParameterCount = cpu_to_le16(params);
1059 pSMB->TotalDataCount = pSMB->DataCount;
1060 pSMB->TotalParameterCount = pSMB->ParameterCount;
1061 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1062 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001063 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001064 pSMB->ByteCount = cpu_to_le16(byte_count);
1065 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1067 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001068 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001069 goto psx_create_err;
1070 }
1071
Joe Perchesf96637b2013-05-04 22:12:25 -05001072 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001073 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1074
Jeff Layton820a8032011-05-04 08:05:26 -04001075 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001076 rc = -EIO; /* bad smb */
1077 goto psx_create_err;
1078 }
1079
1080 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001081 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001082 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001083
Steve French2dd29d32007-04-23 22:07:35 +00001084 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001085 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001086 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1087 /* Let caller know file was created so we can set the mode. */
1088 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001089 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001090 *pOplock |= CIFS_CREATE_ACTION;
1091 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001092 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1093 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001094 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001095 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001096 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001097 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001098 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001099 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001100 goto psx_create_err;
1101 }
Steve French50c2f752007-07-13 00:33:32 +00001102 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001103 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001104 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001105 }
Steve French2dd29d32007-04-23 22:07:35 +00001106
1107psx_create_err:
1108 cifs_buf_release(pSMB);
1109
Steve French65bc98b2009-07-10 15:27:25 +00001110 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001111 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001112 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001113 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001114
1115 if (rc == -EAGAIN)
1116 goto PsxCreat;
1117
Steve French50c2f752007-07-13 00:33:32 +00001118 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001119}
1120
Steve Frencha9d02ad2005-08-24 23:06:05 -07001121static __u16 convert_disposition(int disposition)
1122{
1123 __u16 ofun = 0;
1124
1125 switch (disposition) {
1126 case FILE_SUPERSEDE:
1127 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1128 break;
1129 case FILE_OPEN:
1130 ofun = SMBOPEN_OAPPEND;
1131 break;
1132 case FILE_CREATE:
1133 ofun = SMBOPEN_OCREATE;
1134 break;
1135 case FILE_OPEN_IF:
1136 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1137 break;
1138 case FILE_OVERWRITE:
1139 ofun = SMBOPEN_OTRUNC;
1140 break;
1141 case FILE_OVERWRITE_IF:
1142 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1143 break;
1144 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001145 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001146 ofun = SMBOPEN_OAPPEND; /* regular open */
1147 }
1148 return ofun;
1149}
1150
Jeff Layton35fc37d2008-05-14 10:22:03 -07001151static int
1152access_flags_to_smbopen_mode(const int access_flags)
1153{
1154 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1155
1156 if (masked_flags == GENERIC_READ)
1157 return SMBOPEN_READ;
1158 else if (masked_flags == GENERIC_WRITE)
1159 return SMBOPEN_WRITE;
1160
1161 /* just go for read/write */
1162 return SMBOPEN_READWRITE;
1163}
1164
Steve Frencha9d02ad2005-08-24 23:06:05 -07001165int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001166SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001168 const int access_flags, const int create_options, __u16 *netfid,
1169 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170 const struct nls_table *nls_codepage, int remap)
1171{
1172 int rc = -EACCES;
1173 OPENX_REQ *pSMB = NULL;
1174 OPENX_RSP *pSMBr = NULL;
1175 int bytes_returned;
1176 int name_len;
1177 __u16 count;
1178
1179OldOpenRetry:
1180 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1181 (void **) &pSMBr);
1182 if (rc)
1183 return rc;
1184
1185 pSMB->AndXCommand = 0xFF; /* none */
1186
1187 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1188 count = 1; /* account for one byte pad to word boundary */
1189 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001190 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1191 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001192 name_len++; /* trailing null */
1193 name_len *= 2;
1194 } else { /* BB improve check for buffer overruns BB */
1195 count = 0; /* no pad */
1196 name_len = strnlen(fileName, PATH_MAX);
1197 name_len++; /* trailing null */
1198 strncpy(pSMB->fileName, fileName, name_len);
1199 }
1200 if (*pOplock & REQ_OPLOCK)
1201 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001202 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001203 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001204
Steve Frencha9d02ad2005-08-24 23:06:05 -07001205 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001206 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1208 /* set file as system file if special file such
1209 as fifo and server expecting SFU style and
1210 no Unix extensions */
1211
Steve French790fe572007-07-07 19:25:05 +00001212 if (create_options & CREATE_OPTION_SPECIAL)
1213 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001214 else /* BB FIXME BB */
1215 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216
Jeff Layton67750fb2008-05-09 22:28:02 +00001217 if (create_options & CREATE_OPTION_READONLY)
1218 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219
1220 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001221/* pSMB->CreateOptions = cpu_to_le32(create_options &
1222 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001224
1225 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001226 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001228 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
1230 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001232 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001233 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001235 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 } else {
1237 /* BB verify if wct == 15 */
1238
Steve French582d21e2008-05-13 04:54:12 +00001239/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240
1241 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1242 /* Let caller know file was created so we can set the mode. */
1243 /* Do we care about the CreateAction in any other cases? */
1244 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001245/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 *pOplock |= CIFS_CREATE_ACTION; */
1247 /* BB FIXME END */
1248
Steve French790fe572007-07-07 19:25:05 +00001249 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1251 pfile_info->LastAccessTime = 0; /* BB fixme */
1252 pfile_info->LastWriteTime = 0; /* BB fixme */
1253 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001254 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001255 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001257 pfile_info->AllocationSize =
1258 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1259 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001261 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262 }
1263 }
1264
1265 cifs_buf_release(pSMB);
1266 if (rc == -EAGAIN)
1267 goto OldOpenRetry;
1268 return rc;
1269}
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001272CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1273 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
1275 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001276 OPEN_REQ *req = NULL;
1277 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 int bytes_returned;
1279 int name_len;
1280 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001281 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1282 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001283 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001284 const struct nls_table *nls = cifs_sb->local_nls;
1285 int create_options = oparms->create_options;
1286 int desired_access = oparms->desired_access;
1287 int disposition = oparms->disposition;
1288 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001291 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1292 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 if (rc)
1294 return rc;
1295
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001296 /* no commands go after this */
1297 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001299 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1300 /* account for one byte pad to word boundary */
1301 count = 1;
1302 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1303 path, PATH_MAX, nls, remap);
1304 /* trailing null */
1305 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001307 req->NameLength = cpu_to_le16(name_len);
1308 } else {
1309 /* BB improve check for buffer overruns BB */
1310 /* no pad */
1311 count = 0;
1312 name_len = strnlen(path, PATH_MAX);
1313 /* trailing null */
1314 name_len++;
1315 req->NameLength = cpu_to_le16(name_len);
1316 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001318
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001319 if (*oplock & REQ_OPLOCK)
1320 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1321 else if (*oplock & REQ_BATCHOPLOCK)
1322 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1323
1324 req->DesiredAccess = cpu_to_le32(desired_access);
1325 req->AllocationSize = 0;
1326
1327 /*
1328 * Set file as system file if special file such as fifo and server
1329 * expecting SFU style and no Unix extensions.
1330 */
1331 if (create_options & CREATE_OPTION_SPECIAL)
1332 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1333 else
1334 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1335
1336 /*
1337 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1338 * sensitive checks for other servers such as Samba.
1339 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001341 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Jeff Layton67750fb2008-05-09 22:28:02 +00001343 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001344 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001345
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001346 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1347 req->CreateDisposition = cpu_to_le32(disposition);
1348 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1349
Steve French09d1db52005-04-28 22:41:08 -07001350 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001351 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1352 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
1354 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001355 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001357 req->ByteCount = cpu_to_le16(count);
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1359 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001360 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001362 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001363 cifs_buf_release(req);
1364 if (rc == -EAGAIN)
1365 goto openRetry;
1366 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001368
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001369 /* 1 byte no need to le_to_cpu */
1370 *oplock = rsp->OplockLevel;
1371 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001372 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001373
1374 /* Let caller know file was created so we can set the mode. */
1375 /* Do we care about the CreateAction in any other cases? */
1376 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1377 *oplock |= CIFS_CREATE_ACTION;
1378
1379 if (buf) {
1380 /* copy from CreationTime to Attributes */
1381 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1382 /* the file_info buf is endian converted by caller */
1383 buf->AllocationSize = rsp->AllocationSize;
1384 buf->EndOfFile = rsp->EndOfFile;
1385 buf->NumberOfLinks = cpu_to_le32(1);
1386 buf->DeletePending = 0;
1387 }
1388
1389 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 return rc;
1391}
1392
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001393/*
1394 * Discard any remaining data in the current SMB. To do this, we borrow the
1395 * current bigbuf.
1396 */
1397static int
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001398discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001399{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001400 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001401 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001402
1403 while (remaining > 0) {
1404 int length;
1405
1406 length = cifs_read_from_socket(server, server->bigbuf,
1407 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001408 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001409 if (length < 0)
1410 return length;
1411 server->total_read += length;
1412 remaining -= length;
1413 }
1414
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001415 return 0;
1416}
1417
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001418static int
1419cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1420{
1421 int length;
1422 struct cifs_readdata *rdata = mid->callback_data;
1423
1424 length = discard_remaining_data(server);
1425 dequeue_mid(mid, rdata->result);
1426 return length;
1427}
1428
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001429int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001430cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1431{
1432 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001433 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001434 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001435 char *buf = server->smallbuf;
1436 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001437
Joe Perchesf96637b2013-05-04 22:12:25 -05001438 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1439 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440
1441 /*
1442 * read the rest of READ_RSP header (sans Data array), or whatever we
1443 * can if there's not enough data. At this point, we've read down to
1444 * the Mid.
1445 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001446 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001447 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448
Al Viroa6137302016-01-09 19:37:16 -05001449 length = cifs_read_from_socket(server,
1450 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451 if (length < 0)
1452 return length;
1453 server->total_read += length;
1454
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001455 if (server->ops->is_status_pending &&
1456 server->ops->is_status_pending(buf, server, 0)) {
1457 discard_remaining_data(server);
1458 return -1;
1459 }
1460
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001461 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001462 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001464 cifs_dbg(FYI, "%s: server returned error %d\n",
1465 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001466 return cifs_readv_discard(server, mid);
1467 }
1468
1469 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001470 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001471 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1472 __func__, server->total_read,
1473 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001474 rdata->result = -EIO;
1475 return cifs_readv_discard(server, mid);
1476 }
1477
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001478 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479 if (data_offset < server->total_read) {
1480 /*
1481 * win2k8 sometimes sends an offset of 0 when the read
1482 * is beyond the EOF. Treat it as if the data starts just after
1483 * the header.
1484 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001485 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1486 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001487 data_offset = server->total_read;
1488 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1489 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001490 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1491 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001492 rdata->result = -EIO;
1493 return cifs_readv_discard(server, mid);
1494 }
1495
Joe Perchesf96637b2013-05-04 22:12:25 -05001496 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1497 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001498
1499 len = data_offset - server->total_read;
1500 if (len > 0) {
1501 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001502 length = cifs_read_from_socket(server,
1503 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001504 if (length < 0)
1505 return length;
1506 server->total_read += length;
1507 }
1508
1509 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001510 rdata->iov.iov_base = buf;
1511 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001512 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1513 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514
1515 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001516 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001517 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001518 /* data_len is corrupt -- discard frame */
1519 rdata->result = -EIO;
1520 return cifs_readv_discard(server, mid);
1521 }
1522
Jeff Layton8321fec2012-09-19 06:22:32 -07001523 length = rdata->read_into_pages(server, rdata, data_len);
1524 if (length < 0)
1525 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001526
Jeff Layton8321fec2012-09-19 06:22:32 -07001527 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528
Joe Perchesf96637b2013-05-04 22:12:25 -05001529 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1530 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531
1532 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001533 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001534 return cifs_readv_discard(server, mid);
1535
1536 dequeue_mid(mid, false);
1537 return length;
1538}
1539
1540static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541cifs_readv_callback(struct mid_q_entry *mid)
1542{
1543 struct cifs_readdata *rdata = mid->callback_data;
1544 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1545 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001546 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1547 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001548 .rq_pages = rdata->pages,
1549 .rq_npages = rdata->nr_pages,
1550 .rq_pagesz = rdata->pagesz,
1551 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001552
Joe Perchesf96637b2013-05-04 22:12:25 -05001553 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1554 __func__, mid->mid, mid->mid_state, rdata->result,
1555 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001557 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558 case MID_RESPONSE_RECEIVED:
1559 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001560 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001561 int rc = 0;
1562
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001563 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001564 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001565 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001566 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1567 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001568 }
1569 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001570 task_io_account_read(rdata->got_bytes);
1571 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572 break;
1573 case MID_REQUEST_SUBMITTED:
1574 case MID_RETRY_NEEDED:
1575 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001576 if (server->sign && rdata->got_bytes)
1577 /* reset bytes number since we can not check a sign */
1578 rdata->got_bytes = 0;
1579 /* FIXME: should this be counted toward the initiating task? */
1580 task_io_account_read(rdata->got_bytes);
1581 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001582 break;
1583 default:
1584 rdata->result = -EIO;
1585 }
1586
Jeff Laytonda472fc2012-03-23 14:40:53 -04001587 queue_work(cifsiod_wq, &rdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001588 mutex_lock(&server->srv_mutex);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001589 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001590 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001591 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001592}
1593
1594/* cifs_async_readv - send an async write, and set up mid to handle result */
1595int
1596cifs_async_readv(struct cifs_readdata *rdata)
1597{
1598 int rc;
1599 READ_REQ *smb = NULL;
1600 int wct;
1601 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001602 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001603 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001604
Joe Perchesf96637b2013-05-04 22:12:25 -05001605 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1606 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001607
1608 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1609 wct = 12;
1610 else {
1611 wct = 10; /* old style read */
1612 if ((rdata->offset >> 32) > 0) {
1613 /* can not handle this big offset for old */
1614 return -EIO;
1615 }
1616 }
1617
1618 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1619 if (rc)
1620 return rc;
1621
1622 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1623 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1624
1625 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001626 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001627 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1628 if (wct == 12)
1629 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1630 smb->Remaining = 0;
1631 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1632 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1633 if (wct == 12)
1634 smb->ByteCount = 0;
1635 else {
1636 /* old style read */
1637 struct smb_com_readx_req *smbr =
1638 (struct smb_com_readx_req *)smb;
1639 smbr->ByteCount = 0;
1640 }
1641
1642 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001643 rdata->iov.iov_base = smb;
1644 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001645
Jeff Layton6993f742012-05-16 07:13:17 -04001646 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001647 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1648 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001649
1650 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001651 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001652 else
1653 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001654
1655 cifs_small_buf_release(smb);
1656 return rc;
1657}
1658
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001660CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1661 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662{
1663 int rc = -EACCES;
1664 READ_REQ *pSMB = NULL;
1665 READ_RSP *pSMBr = NULL;
1666 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001667 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001668 int resp_buf_type = 0;
1669 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001670 __u32 pid = io_parms->pid;
1671 __u16 netfid = io_parms->netfid;
1672 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001673 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001674 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
Joe Perchesf96637b2013-05-04 22:12:25 -05001676 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001677 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001678 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001679 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001680 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001681 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001682 /* can not handle this big offset for old */
1683 return -EIO;
1684 }
1685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001688 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 if (rc)
1690 return rc;
1691
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001692 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1693 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 /* tcon and ses pointer are checked in smb_init */
1696 if (tcon->ses->server == NULL)
1697 return -ECONNABORTED;
1698
Steve Frenchec637e32005-12-12 20:53:18 -08001699 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001701 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001702 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001703 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 pSMB->Remaining = 0;
1706 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1707 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001708 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001709 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1710 else {
1711 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001712 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001713 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001714 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001715 }
Steve Frenchec637e32005-12-12 20:53:18 -08001716
1717 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001718 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001719 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001720 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001721 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001722 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001724 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 } else {
1726 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1727 data_length = data_length << 16;
1728 data_length += le16_to_cpu(pSMBr->DataLength);
1729 *nbytes = data_length;
1730
1731 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001732 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001734 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001735 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 rc = -EIO;
1737 *nbytes = 0;
1738 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001739 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001740 le16_to_cpu(pSMBr->DataOffset);
1741/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001742 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001743 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001744 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001745 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001746 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
1748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
Steve French4b8f9302006-02-26 16:41:18 +00001750/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001751 if (*buf) {
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01001752 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001753 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001754 /* return buffer to caller to free */
1755 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001756 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001757 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001758 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001759 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001760 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001761
1762 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 since file handle passed in no longer valid */
1764 return rc;
1765}
1766
Steve Frenchec637e32005-12-12 20:53:18 -08001767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001769CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001770 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
1772 int rc = -EACCES;
1773 WRITE_REQ *pSMB = NULL;
1774 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001775 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 __u32 bytes_sent;
1777 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001778 __u32 pid = io_parms->pid;
1779 __u16 netfid = io_parms->netfid;
1780 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001781 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001782 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
Steve Frencha24e2d72010-04-03 17:20:21 +00001784 *nbytes = 0;
1785
Joe Perchesf96637b2013-05-04 22:12:25 -05001786 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001787 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001788 return -ECONNABORTED;
1789
Steve French790fe572007-07-07 19:25:05 +00001790 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001791 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001792 else {
Steve French1c955182005-08-30 20:58:07 -07001793 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001794 if ((offset >> 32) > 0) {
1795 /* can not handle big offset for old srv */
1796 return -EIO;
1797 }
1798 }
Steve French1c955182005-08-30 20:58:07 -07001799
1800 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 (void **) &pSMBr);
1802 if (rc)
1803 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001804
1805 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1806 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 /* tcon and ses pointer are checked in smb_init */
1809 if (tcon->ses->server == NULL)
1810 return -ECONNABORTED;
1811
1812 pSMB->AndXCommand = 0xFF; /* none */
1813 pSMB->Fid = netfid;
1814 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001815 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001816 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 pSMB->Reserved = 0xFFFFFFFF;
1819 pSMB->WriteMode = 0;
1820 pSMB->Remaining = 0;
1821
Steve French50c2f752007-07-13 00:33:32 +00001822 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 can send more if LARGE_WRITE_X capability returned by the server and if
1824 our buffer is big enough or if we convert to iovecs on socket writes
1825 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001826 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1828 } else {
1829 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1830 & ~0xFF;
1831 }
1832
1833 if (bytes_sent > count)
1834 bytes_sent = count;
1835 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001836 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001837 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001838 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001839 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 /* No buffer */
1841 cifs_buf_release(pSMB);
1842 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001843 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001844 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001845 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001846 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001847 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1850 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001851 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001852
Steve French790fe572007-07-07 19:25:05 +00001853 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001854 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001855 else { /* old style write has byte count 4 bytes earlier
1856 so 4 bytes pad */
1857 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001858 (struct smb_com_writex_req *)pSMB;
1859 pSMBW->ByteCount = cpu_to_le16(byte_count);
1860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
1862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001864 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001866 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 } else {
1868 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1869 *nbytes = (*nbytes) << 16;
1870 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301871
1872 /*
1873 * Mask off high 16 bits when bytes written as returned by the
1874 * server is greater than bytes requested by the client. Some
1875 * OS/2 servers are known to set incorrect CountHigh values.
1876 */
1877 if (*nbytes > count)
1878 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 }
1880
1881 cifs_buf_release(pSMB);
1882
Steve French50c2f752007-07-13 00:33:32 +00001883 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 since file handle passed in no longer valid */
1885
1886 return rc;
1887}
1888
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001889void
1890cifs_writedata_release(struct kref *refcount)
1891{
1892 struct cifs_writedata *wdata = container_of(refcount,
1893 struct cifs_writedata, refcount);
1894
1895 if (wdata->cfile)
1896 cifsFileInfo_put(wdata->cfile);
1897
1898 kfree(wdata);
1899}
1900
1901/*
1902 * Write failed with a retryable error. Resend the write request. It's also
1903 * possible that the page was redirtied so re-clean the page.
1904 */
1905static void
1906cifs_writev_requeue(struct cifs_writedata *wdata)
1907{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001908 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001909 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001910 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001911 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001912
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001913 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1914 i = 0;
1915 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001916 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001917 struct cifs_writedata *wdata2;
1918 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001919
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001920 wsize = server->ops->wp_retry_size(inode);
1921 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001922 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001923 if (!nr_pages) {
1924 rc = -ENOTSUPP;
1925 break;
1926 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001927 cur_len = nr_pages * PAGE_SIZE;
1928 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001929 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001930 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001931 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001932 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001933 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001934
1935 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1936 if (!wdata2) {
1937 rc = -ENOMEM;
1938 break;
1939 }
1940
1941 for (j = 0; j < nr_pages; j++) {
1942 wdata2->pages[j] = wdata->pages[i + j];
1943 lock_page(wdata2->pages[j]);
1944 clear_page_dirty_for_io(wdata2->pages[j]);
1945 }
1946
1947 wdata2->sync_mode = wdata->sync_mode;
1948 wdata2->nr_pages = nr_pages;
1949 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001950 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001951 wdata2->tailsz = tailsz;
1952 wdata2->bytes = cur_len;
1953
1954 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1955 if (!wdata2->cfile) {
1956 cifs_dbg(VFS, "No writable handles for inode\n");
1957 rc = -EBADF;
1958 break;
1959 }
1960 wdata2->pid = wdata2->cfile->pid;
1961 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1962
1963 for (j = 0; j < nr_pages; j++) {
1964 unlock_page(wdata2->pages[j]);
1965 if (rc != 0 && rc != -EAGAIN) {
1966 SetPageError(wdata2->pages[j]);
1967 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001968 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001969 }
1970 }
1971
1972 if (rc) {
1973 kref_put(&wdata2->refcount, cifs_writedata_release);
1974 if (rc == -EAGAIN)
1975 continue;
1976 break;
1977 }
1978
1979 rest_len -= cur_len;
1980 i += nr_pages;
1981 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001982
1983 mapping_set_error(inode->i_mapping, rc);
1984 kref_put(&wdata->refcount, cifs_writedata_release);
1985}
1986
Jeff Laytonc2e87642012-03-23 14:40:55 -04001987void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001988cifs_writev_complete(struct work_struct *work)
1989{
1990 struct cifs_writedata *wdata = container_of(work,
1991 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00001992 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001993 int i = 0;
1994
1995 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001996 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001997 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001998 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001999 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2000 wdata->bytes);
2001 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2002 return cifs_writev_requeue(wdata);
2003
2004 for (i = 0; i < wdata->nr_pages; i++) {
2005 struct page *page = wdata->pages[i];
2006 if (wdata->result == -EAGAIN)
2007 __set_page_dirty_nobuffers(page);
2008 else if (wdata->result < 0)
2009 SetPageError(page);
2010 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002011 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002012 }
2013 if (wdata->result != -EAGAIN)
2014 mapping_set_error(inode->i_mapping, wdata->result);
2015 kref_put(&wdata->refcount, cifs_writedata_release);
2016}
2017
2018struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002019cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002020{
2021 struct cifs_writedata *wdata;
2022
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002023 /* writedata + number of page pointers */
2024 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002025 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002026 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002027 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002028 INIT_LIST_HEAD(&wdata->list);
2029 init_completion(&wdata->done);
2030 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002031 }
2032 return wdata;
2033}
2034
2035/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002036 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002037 * workqueue completion task.
2038 */
2039static void
2040cifs_writev_callback(struct mid_q_entry *mid)
2041{
2042 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002043 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002044 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002045 unsigned int written;
2046 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2047
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002048 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002049 case MID_RESPONSE_RECEIVED:
2050 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2051 if (wdata->result != 0)
2052 break;
2053
2054 written = le16_to_cpu(smb->CountHigh);
2055 written <<= 16;
2056 written += le16_to_cpu(smb->Count);
2057 /*
2058 * Mask off high 16 bits when bytes written as returned
2059 * by the server is greater than bytes requested by the
2060 * client. OS/2 servers are known to set incorrect
2061 * CountHigh values.
2062 */
2063 if (written > wdata->bytes)
2064 written &= 0xFFFF;
2065
2066 if (written < wdata->bytes)
2067 wdata->result = -ENOSPC;
2068 else
2069 wdata->bytes = written;
2070 break;
2071 case MID_REQUEST_SUBMITTED:
2072 case MID_RETRY_NEEDED:
2073 wdata->result = -EAGAIN;
2074 break;
2075 default:
2076 wdata->result = -EIO;
2077 break;
2078 }
2079
Jeff Laytonda472fc2012-03-23 14:40:53 -04002080 queue_work(cifsiod_wq, &wdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002081 mutex_lock(&server->srv_mutex);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002083 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002084 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002085}
2086
2087/* cifs_async_writev - send an async write, and set up mid to handle result */
2088int
Steve French4a5c80d2014-02-07 20:45:12 -06002089cifs_async_writev(struct cifs_writedata *wdata,
2090 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002091{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002092 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002093 WRITE_REQ *smb = NULL;
2094 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002095 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002096 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002097 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002098
2099 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2100 wct = 14;
2101 } else {
2102 wct = 12;
2103 if (wdata->offset >> 32 > 0) {
2104 /* can not handle big offset for old srv */
2105 return -EIO;
2106 }
2107 }
2108
2109 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2110 if (rc)
2111 goto async_writev_out;
2112
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002113 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2114 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002115
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002116 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002117 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002118 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2119 if (wct == 14)
2120 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2121 smb->Reserved = 0xFFFFFFFF;
2122 smb->WriteMode = 0;
2123 smb->Remaining = 0;
2124
2125 smb->DataOffset =
2126 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2127
2128 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002129 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2130 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002131
Jeff Laytoneddb0792012-09-18 16:20:35 -07002132 rqst.rq_iov = &iov;
2133 rqst.rq_nvec = 1;
2134 rqst.rq_pages = wdata->pages;
2135 rqst.rq_npages = wdata->nr_pages;
2136 rqst.rq_pagesz = wdata->pagesz;
2137 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002138
Joe Perchesf96637b2013-05-04 22:12:25 -05002139 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2140 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002141
2142 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2143 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2144
2145 if (wct == 14) {
2146 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2147 put_bcc(wdata->bytes + 1, &smb->hdr);
2148 } else {
2149 /* wct == 12 */
2150 struct smb_com_writex_req *smbw =
2151 (struct smb_com_writex_req *)smb;
2152 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2153 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002154 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002155 }
2156
2157 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002158 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2159 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002160
2161 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002162 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002163 else
Steve French4a5c80d2014-02-07 20:45:12 -06002164 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002165
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002166async_writev_out:
2167 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002168 return rc;
2169}
2170
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002171int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002172CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002173 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174{
2175 int rc = -EACCES;
2176 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002177 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002178 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002179 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002180 __u32 pid = io_parms->pid;
2181 __u16 netfid = io_parms->netfid;
2182 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002183 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002184 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002186 *nbytes = 0;
2187
Joe Perchesf96637b2013-05-04 22:12:25 -05002188 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002189
Steve French4c3130e2008-12-09 00:28:16 +00002190 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002191 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002192 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002193 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002194 if ((offset >> 32) > 0) {
2195 /* can not handle big offset for old srv */
2196 return -EIO;
2197 }
2198 }
Steve French8cc64c62005-10-03 13:49:43 -07002199 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 if (rc)
2201 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002202
2203 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2204 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2205
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 /* tcon and ses pointer are checked in smb_init */
2207 if (tcon->ses->server == NULL)
2208 return -ECONNABORTED;
2209
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002210 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 pSMB->Fid = netfid;
2212 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002213 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002214 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 pSMB->Reserved = 0xFFFFFFFF;
2216 pSMB->WriteMode = 0;
2217 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002218
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002220 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
Steve French3e844692005-10-03 13:37:24 -07002222 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2223 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002224 /* header + 1 byte pad */
2225 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002226 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002227 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002228 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002229 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002230 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002231 pSMB->ByteCount = cpu_to_le16(count + 1);
2232 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002233 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002234 (struct smb_com_writex_req *)pSMB;
2235 pSMBW->ByteCount = cpu_to_le16(count + 5);
2236 }
Steve French3e844692005-10-03 13:37:24 -07002237 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002238 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002239 iov[0].iov_len = smb_hdr_len + 4;
2240 else /* wct == 12 pad bigger by four bytes */
2241 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002242
Steve French3e844692005-10-03 13:37:24 -07002243
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002244 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002245 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002247 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002248 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002249 /* presumably this can not happen, but best to be safe */
2250 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002251 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002252 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002253 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2254 *nbytes = (*nbytes) << 16;
2255 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302256
2257 /*
2258 * Mask off high 16 bits when bytes written as returned by the
2259 * server is greater than bytes requested by the client. OS/2
2260 * servers are known to set incorrect CountHigh values.
2261 */
2262 if (*nbytes > count)
2263 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
Steve French4b8f9302006-02-26 16:41:18 +00002266/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002267 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
Steve French50c2f752007-07-13 00:33:32 +00002269 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 since file handle passed in no longer valid */
2271
2272 return rc;
2273}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002274
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002275int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2276 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002277 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2278{
2279 int rc = 0;
2280 LOCK_REQ *pSMB = NULL;
2281 struct kvec iov[2];
2282 int resp_buf_type;
2283 __u16 count;
2284
Joe Perchesf96637b2013-05-04 22:12:25 -05002285 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2286 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002287
2288 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2289 if (rc)
2290 return rc;
2291
2292 pSMB->Timeout = 0;
2293 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2294 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2295 pSMB->LockType = lock_type;
2296 pSMB->AndXCommand = 0xFF; /* none */
2297 pSMB->Fid = netfid; /* netfid stays le */
2298
2299 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2300 inc_rfc1001_len(pSMB, count);
2301 pSMB->ByteCount = cpu_to_le16(count);
2302
2303 iov[0].iov_base = (char *)pSMB;
2304 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2305 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2306 iov[1].iov_base = (char *)buf;
2307 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2308
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002309 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002310 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2311 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002312 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002313
2314 return rc;
2315}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002316
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002318CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002319 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002321 const __u32 numLock, const __u8 lockType,
2322 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323{
2324 int rc = 0;
2325 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002326/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002328 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 __u16 count;
2330
Joe Perchesf96637b2013-05-04 22:12:25 -05002331 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2332 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002333 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2334
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 if (rc)
2336 return rc;
2337
Steve French790fe572007-07-07 19:25:05 +00002338 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002339 /* no response expected */
2340 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002342 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002343 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2345 } else {
2346 pSMB->Timeout = 0;
2347 }
2348
2349 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2350 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2351 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002352 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 pSMB->AndXCommand = 0xFF; /* none */
2354 pSMB->Fid = smb_file_id; /* netfid stays le */
2355
Steve French790fe572007-07-07 19:25:05 +00002356 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002357 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 /* BB where to store pid high? */
2359 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2360 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2361 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2362 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2363 count = sizeof(LOCKING_ANDX_RANGE);
2364 } else {
2365 /* oplock break */
2366 count = 0;
2367 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002368 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 pSMB->ByteCount = cpu_to_le16(count);
2370
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002371 if (waitFlag) {
2372 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002373 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002374 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002375 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002376 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002377 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002378 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002379 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002380 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002381 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Steve French50c2f752007-07-13 00:33:32 +00002383 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 since file handle passed in no longer valid */
2385 return rc;
2386}
2387
2388int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002389CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002390 const __u16 smb_file_id, const __u32 netpid,
2391 const loff_t start_offset, const __u64 len,
2392 struct file_lock *pLockData, const __u16 lock_type,
2393 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002394{
2395 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2396 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002397 struct cifs_posix_lock *parm_data;
2398 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002399 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002400 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002401 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002402 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002403 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002404
Joe Perchesf96637b2013-05-04 22:12:25 -05002405 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002406
Steve French08547b02006-02-28 22:39:25 +00002407 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2408
2409 if (rc)
2410 return rc;
2411
2412 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2413
Steve French50c2f752007-07-13 00:33:32 +00002414 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002415 pSMB->MaxSetupCount = 0;
2416 pSMB->Reserved = 0;
2417 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002418 pSMB->Reserved2 = 0;
2419 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2420 offset = param_offset + params;
2421
Steve French08547b02006-02-28 22:39:25 +00002422 count = sizeof(struct cifs_posix_lock);
2423 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002424 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002425 pSMB->SetupCount = 1;
2426 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002427 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002428 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2429 else
2430 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2431 byte_count = 3 /* pad */ + params + count;
2432 pSMB->DataCount = cpu_to_le16(count);
2433 pSMB->ParameterCount = cpu_to_le16(params);
2434 pSMB->TotalDataCount = pSMB->DataCount;
2435 pSMB->TotalParameterCount = pSMB->ParameterCount;
2436 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002437 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002438 (((char *) &pSMB->hdr.Protocol) + offset);
2439
2440 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002441 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002442 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002443 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002444 pSMB->Timeout = cpu_to_le32(-1);
2445 } else
2446 pSMB->Timeout = 0;
2447
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002448 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002449 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002450 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002451
2452 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002453 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002454 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2455 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002456 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002457 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002458 if (waitFlag) {
2459 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2460 (struct smb_hdr *) pSMBr, &bytes_returned);
2461 } else {
Steve French133672e2007-11-13 22:41:37 +00002462 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002463 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002464 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2465 &resp_buf_type, timeout);
2466 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2467 not try to free it twice below on exit */
2468 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002469 }
2470
Steve French08547b02006-02-28 22:39:25 +00002471 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002472 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002473 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002474 /* lock structure can be returned on get */
2475 __u16 data_offset;
2476 __u16 data_count;
2477 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002478
Jeff Layton820a8032011-05-04 08:05:26 -04002479 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002480 rc = -EIO; /* bad smb */
2481 goto plk_err_exit;
2482 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002483 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2484 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002485 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002486 rc = -EIO;
2487 goto plk_err_exit;
2488 }
2489 parm_data = (struct cifs_posix_lock *)
2490 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002491 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002492 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002493 else {
2494 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002495 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002496 pLockData->fl_type = F_RDLCK;
2497 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002498 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002499 pLockData->fl_type = F_WRLCK;
2500
Steve French5443d132011-03-13 05:08:25 +00002501 pLockData->fl_start = le64_to_cpu(parm_data->start);
2502 pLockData->fl_end = pLockData->fl_start +
2503 le64_to_cpu(parm_data->length) - 1;
2504 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002505 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002506 }
Steve French50c2f752007-07-13 00:33:32 +00002507
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002508plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002509 if (pSMB)
2510 cifs_small_buf_release(pSMB);
2511
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002512 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French133672e2007-11-13 22:41:37 +00002513
Steve French08547b02006-02-28 22:39:25 +00002514 /* Note: On -EAGAIN error only caller can retry on handle based calls
2515 since file handle passed in no longer valid */
2516
2517 return rc;
2518}
2519
2520
2521int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002522CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
2524 int rc = 0;
2525 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002526 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
2528/* do not retry on dead session on close */
2529 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002530 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 return 0;
2532 if (rc)
2533 return rc;
2534
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002536 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002538 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002539 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002541 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002543 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 }
2545 }
2546
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002548 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 rc = 0;
2550
2551 return rc;
2552}
2553
2554int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002555CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002556{
2557 int rc = 0;
2558 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002559 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002560
2561 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2562 if (rc)
2563 return rc;
2564
2565 pSMB->FileID = (__u16) smb_file_id;
2566 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002567 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002568 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002569 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002570 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002571
2572 return rc;
2573}
2574
2575int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002576CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002577 const char *from_name, const char *to_name,
2578 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579{
2580 int rc = 0;
2581 RENAME_REQ *pSMB = NULL;
2582 RENAME_RSP *pSMBr = NULL;
2583 int bytes_returned;
2584 int name_len, name_len2;
2585 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002586 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
Joe Perchesf96637b2013-05-04 22:12:25 -05002588 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589renameRetry:
2590 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2591 (void **) &pSMBr);
2592 if (rc)
2593 return rc;
2594
2595 pSMB->BufferFormat = 0x04;
2596 pSMB->SearchAttributes =
2597 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2598 ATTR_DIRECTORY);
2599
2600 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002601 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2602 from_name, PATH_MAX,
2603 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 name_len++; /* trailing null */
2605 name_len *= 2;
2606 pSMB->OldFileName[name_len] = 0x04; /* pad */
2607 /* protocol requires ASCII signature byte on Unicode string */
2608 pSMB->OldFileName[name_len + 1] = 0x00;
2609 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002610 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002611 to_name, PATH_MAX, cifs_sb->local_nls,
2612 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2614 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002615 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002616 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002618 strncpy(pSMB->OldFileName, from_name, name_len);
2619 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 name_len2++; /* trailing null */
2621 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002622 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 name_len2++; /* trailing null */
2624 name_len2++; /* signature byte */
2625 }
2626
2627 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002628 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 pSMB->ByteCount = cpu_to_le16(count);
2630
2631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002633 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002634 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002635 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 cifs_buf_release(pSMB);
2638
2639 if (rc == -EAGAIN)
2640 goto renameRetry;
2641
2642 return rc;
2643}
2644
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002645int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002646 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002647 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648{
2649 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2650 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002651 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 char *data_offset;
2653 char dummy_string[30];
2654 int rc = 0;
2655 int bytes_returned = 0;
2656 int len_of_str;
2657 __u16 params, param_offset, offset, count, byte_count;
2658
Joe Perchesf96637b2013-05-04 22:12:25 -05002659 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2661 (void **) &pSMBr);
2662 if (rc)
2663 return rc;
2664
2665 params = 6;
2666 pSMB->MaxSetupCount = 0;
2667 pSMB->Reserved = 0;
2668 pSMB->Flags = 0;
2669 pSMB->Timeout = 0;
2670 pSMB->Reserved2 = 0;
2671 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2672 offset = param_offset + params;
2673
2674 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2675 rename_info = (struct set_file_rename *) data_offset;
2676 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002677 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 pSMB->SetupCount = 1;
2679 pSMB->Reserved3 = 0;
2680 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2681 byte_count = 3 /* pad */ + params;
2682 pSMB->ParameterCount = cpu_to_le16(params);
2683 pSMB->TotalParameterCount = pSMB->ParameterCount;
2684 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2685 pSMB->DataOffset = cpu_to_le16(offset);
2686 /* construct random name ".cifs_tmp<inodenum><mid>" */
2687 rename_info->overwrite = cpu_to_le32(1);
2688 rename_info->root_fid = 0;
2689 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002690 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002691 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002692 len_of_str =
2693 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002694 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002696 len_of_str =
2697 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002698 target_name, PATH_MAX, nls_codepage,
2699 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 }
2701 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002702 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 byte_count += count;
2704 pSMB->DataCount = cpu_to_le16(count);
2705 pSMB->TotalDataCount = pSMB->DataCount;
2706 pSMB->Fid = netfid;
2707 pSMB->InformationLevel =
2708 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2709 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002710 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 pSMB->ByteCount = cpu_to_le16(byte_count);
2712 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002713 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002714 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002715 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002716 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2717 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002718
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 cifs_buf_release(pSMB);
2720
2721 /* Note: On -EAGAIN error only caller can retry on handle based calls
2722 since file handle passed in no longer valid */
2723
2724 return rc;
2725}
2726
2727int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002728CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2729 const char *fromName, const __u16 target_tid, const char *toName,
2730 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731{
2732 int rc = 0;
2733 COPY_REQ *pSMB = NULL;
2734 COPY_RSP *pSMBr = NULL;
2735 int bytes_returned;
2736 int name_len, name_len2;
2737 __u16 count;
2738
Joe Perchesf96637b2013-05-04 22:12:25 -05002739 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740copyRetry:
2741 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2742 (void **) &pSMBr);
2743 if (rc)
2744 return rc;
2745
2746 pSMB->BufferFormat = 0x04;
2747 pSMB->Tid2 = target_tid;
2748
2749 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2750
2751 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002752 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2753 fromName, PATH_MAX, nls_codepage,
2754 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 name_len++; /* trailing null */
2756 name_len *= 2;
2757 pSMB->OldFileName[name_len] = 0x04; /* pad */
2758 /* protocol requires ASCII signature byte on Unicode string */
2759 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002760 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002761 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2762 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2764 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002765 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 name_len = strnlen(fromName, PATH_MAX);
2767 name_len++; /* trailing null */
2768 strncpy(pSMB->OldFileName, fromName, name_len);
2769 name_len2 = strnlen(toName, PATH_MAX);
2770 name_len2++; /* trailing null */
2771 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2772 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2773 name_len2++; /* trailing null */
2774 name_len2++; /* signature byte */
2775 }
2776
2777 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002778 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 pSMB->ByteCount = cpu_to_le16(count);
2780
2781 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2782 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2783 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002784 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2785 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 }
Steve French0d817bc2008-05-22 02:02:03 +00002787 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789 if (rc == -EAGAIN)
2790 goto copyRetry;
2791
2792 return rc;
2793}
2794
2795int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002796CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002798 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799{
2800 TRANSACTION2_SPI_REQ *pSMB = NULL;
2801 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2802 char *data_offset;
2803 int name_len;
2804 int name_len_target;
2805 int rc = 0;
2806 int bytes_returned = 0;
2807 __u16 params, param_offset, offset, byte_count;
2808
Joe Perchesf96637b2013-05-04 22:12:25 -05002809 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810createSymLinkRetry:
2811 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2812 (void **) &pSMBr);
2813 if (rc)
2814 return rc;
2815
2816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2817 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002818 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2819 /* find define for this maxpathcomponent */
2820 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 name_len++; /* trailing null */
2822 name_len *= 2;
2823
Steve French50c2f752007-07-13 00:33:32 +00002824 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 name_len = strnlen(fromName, PATH_MAX);
2826 name_len++; /* trailing null */
2827 strncpy(pSMB->FileName, fromName, name_len);
2828 }
2829 params = 6 + name_len;
2830 pSMB->MaxSetupCount = 0;
2831 pSMB->Reserved = 0;
2832 pSMB->Flags = 0;
2833 pSMB->Timeout = 0;
2834 pSMB->Reserved2 = 0;
2835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002836 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 offset = param_offset + params;
2838
2839 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2841 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002842 cifsConvertToUTF16((__le16 *) data_offset, toName,
2843 /* find define for this maxpathcomponent */
2844 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 name_len_target++; /* trailing null */
2846 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002847 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 name_len_target = strnlen(toName, PATH_MAX);
2849 name_len_target++; /* trailing null */
2850 strncpy(data_offset, toName, name_len_target);
2851 }
2852
2853 pSMB->MaxParameterCount = cpu_to_le16(2);
2854 /* BB find exact max on data count below from sess */
2855 pSMB->MaxDataCount = cpu_to_le16(1000);
2856 pSMB->SetupCount = 1;
2857 pSMB->Reserved3 = 0;
2858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2859 byte_count = 3 /* pad */ + params + name_len_target;
2860 pSMB->DataCount = cpu_to_le16(name_len_target);
2861 pSMB->ParameterCount = cpu_to_le16(params);
2862 pSMB->TotalDataCount = pSMB->DataCount;
2863 pSMB->TotalParameterCount = pSMB->ParameterCount;
2864 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2865 pSMB->DataOffset = cpu_to_le16(offset);
2866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2867 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002868 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 pSMB->ByteCount = cpu_to_le16(byte_count);
2870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002872 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002873 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002874 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2875 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
Steve French0d817bc2008-05-22 02:02:03 +00002877 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878
2879 if (rc == -EAGAIN)
2880 goto createSymLinkRetry;
2881
2882 return rc;
2883}
2884
2885int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002886CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002888 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
2890 TRANSACTION2_SPI_REQ *pSMB = NULL;
2891 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2892 char *data_offset;
2893 int name_len;
2894 int name_len_target;
2895 int rc = 0;
2896 int bytes_returned = 0;
2897 __u16 params, param_offset, offset, byte_count;
2898
Joe Perchesf96637b2013-05-04 22:12:25 -05002899 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900createHardLinkRetry:
2901 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2902 (void **) &pSMBr);
2903 if (rc)
2904 return rc;
2905
2906 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002907 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2908 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 name_len++; /* trailing null */
2910 name_len *= 2;
2911
Steve French50c2f752007-07-13 00:33:32 +00002912 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 name_len = strnlen(toName, PATH_MAX);
2914 name_len++; /* trailing null */
2915 strncpy(pSMB->FileName, toName, name_len);
2916 }
2917 params = 6 + name_len;
2918 pSMB->MaxSetupCount = 0;
2919 pSMB->Reserved = 0;
2920 pSMB->Flags = 0;
2921 pSMB->Timeout = 0;
2922 pSMB->Reserved2 = 0;
2923 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002924 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 offset = param_offset + params;
2926
2927 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2929 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002930 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2931 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 name_len_target++; /* trailing null */
2933 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002934 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 name_len_target = strnlen(fromName, PATH_MAX);
2936 name_len_target++; /* trailing null */
2937 strncpy(data_offset, fromName, name_len_target);
2938 }
2939
2940 pSMB->MaxParameterCount = cpu_to_le16(2);
2941 /* BB find exact max on data count below from sess*/
2942 pSMB->MaxDataCount = cpu_to_le16(1000);
2943 pSMB->SetupCount = 1;
2944 pSMB->Reserved3 = 0;
2945 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2946 byte_count = 3 /* pad */ + params + name_len_target;
2947 pSMB->ParameterCount = cpu_to_le16(params);
2948 pSMB->TotalParameterCount = pSMB->ParameterCount;
2949 pSMB->DataCount = cpu_to_le16(name_len_target);
2950 pSMB->TotalDataCount = pSMB->DataCount;
2951 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2952 pSMB->DataOffset = cpu_to_le16(offset);
2953 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2954 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002955 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 pSMB->ByteCount = cpu_to_le16(byte_count);
2957 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2958 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002959 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002960 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002961 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2962 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963
2964 cifs_buf_release(pSMB);
2965 if (rc == -EAGAIN)
2966 goto createHardLinkRetry;
2967
2968 return rc;
2969}
2970
2971int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002972CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002973 const char *from_name, const char *to_name,
2974 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975{
2976 int rc = 0;
2977 NT_RENAME_REQ *pSMB = NULL;
2978 RENAME_RSP *pSMBr = NULL;
2979 int bytes_returned;
2980 int name_len, name_len2;
2981 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002982 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
Joe Perchesf96637b2013-05-04 22:12:25 -05002984 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985winCreateHardLinkRetry:
2986
2987 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2988 (void **) &pSMBr);
2989 if (rc)
2990 return rc;
2991
2992 pSMB->SearchAttributes =
2993 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2994 ATTR_DIRECTORY);
2995 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2996 pSMB->ClusterCount = 0;
2997
2998 pSMB->BufferFormat = 0x04;
2999
3000 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3001 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003002 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3003 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 name_len++; /* trailing null */
3005 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003006
3007 /* protocol specifies ASCII buffer format (0x04) for unicode */
3008 pSMB->OldFileName[name_len] = 0x04;
3009 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003011 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003012 to_name, PATH_MAX, cifs_sb->local_nls,
3013 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3015 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003016 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003017 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003019 strncpy(pSMB->OldFileName, from_name, name_len);
3020 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 name_len2++; /* trailing null */
3022 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003023 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 name_len2++; /* trailing null */
3025 name_len2++; /* signature byte */
3026 }
3027
3028 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003029 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 pSMB->ByteCount = cpu_to_le16(count);
3031
3032 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3033 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003034 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003035 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003036 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003037
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 cifs_buf_release(pSMB);
3039 if (rc == -EAGAIN)
3040 goto winCreateHardLinkRetry;
3041
3042 return rc;
3043}
3044
3045int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003046CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003047 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003048 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049{
3050/* SMB_QUERY_FILE_UNIX_LINK */
3051 TRANSACTION2_QPI_REQ *pSMB = NULL;
3052 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3053 int rc = 0;
3054 int bytes_returned;
3055 int name_len;
3056 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003057 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
Joe Perchesf96637b2013-05-04 22:12:25 -05003059 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
3061querySymLinkRetry:
3062 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3063 (void **) &pSMBr);
3064 if (rc)
3065 return rc;
3066
3067 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3068 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003069 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3070 searchName, PATH_MAX, nls_codepage,
3071 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 name_len++; /* trailing null */
3073 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003074 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 name_len = strnlen(searchName, PATH_MAX);
3076 name_len++; /* trailing null */
3077 strncpy(pSMB->FileName, searchName, name_len);
3078 }
3079
3080 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3081 pSMB->TotalDataCount = 0;
3082 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003083 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 pSMB->MaxSetupCount = 0;
3085 pSMB->Reserved = 0;
3086 pSMB->Flags = 0;
3087 pSMB->Timeout = 0;
3088 pSMB->Reserved2 = 0;
3089 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003090 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 pSMB->DataCount = 0;
3092 pSMB->DataOffset = 0;
3093 pSMB->SetupCount = 1;
3094 pSMB->Reserved3 = 0;
3095 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3096 byte_count = params + 1 /* pad */ ;
3097 pSMB->TotalParameterCount = cpu_to_le16(params);
3098 pSMB->ParameterCount = pSMB->TotalParameterCount;
3099 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3100 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003101 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 pSMB->ByteCount = cpu_to_le16(byte_count);
3103
3104 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3106 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003107 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 } else {
3109 /* decode response */
3110
3111 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003113 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003114 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003116 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003117 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118
Jeff Layton460b9692009-04-30 07:17:56 -04003119 data_start = ((char *) &pSMBr->hdr.Protocol) +
3120 le16_to_cpu(pSMBr->t2.DataOffset);
3121
Steve French0e0d2cf2009-05-01 05:27:32 +00003122 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3123 is_unicode = true;
3124 else
3125 is_unicode = false;
3126
Steve French737b7582005-04-28 22:41:06 -07003127 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003128 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3129 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003130 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003131 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 }
3133 }
3134 cifs_buf_release(pSMB);
3135 if (rc == -EAGAIN)
3136 goto querySymLinkRetry;
3137 return rc;
3138}
3139
Steve Frenchc52a9552011-02-24 06:16:22 +00003140/*
3141 * Recent Windows versions now create symlinks more frequently
3142 * and they use the "reparse point" mechanism below. We can of course
3143 * do symlinks nicely to Samba and other servers which support the
3144 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3145 * "MF" symlinks optionally, but for recent Windows we really need to
3146 * reenable the code below and fix the cifs_symlink callers to handle this.
3147 * In the interim this code has been moved to its own config option so
3148 * it is not compiled in by default until callers fixed up and more tested.
3149 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003151CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3152 __u16 fid, char **symlinkinfo,
3153 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154{
3155 int rc = 0;
3156 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003157 struct smb_com_transaction_ioctl_req *pSMB;
3158 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003159 bool is_unicode;
3160 unsigned int sub_len;
3161 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003162 struct reparse_symlink_data *reparse_buf;
3163 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003164 __u32 data_offset, data_count;
3165 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003167 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3169 (void **) &pSMBr);
3170 if (rc)
3171 return rc;
3172
3173 pSMB->TotalParameterCount = 0 ;
3174 pSMB->TotalDataCount = 0;
3175 pSMB->MaxParameterCount = cpu_to_le32(2);
3176 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003177 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 pSMB->MaxSetupCount = 4;
3179 pSMB->Reserved = 0;
3180 pSMB->ParameterOffset = 0;
3181 pSMB->DataCount = 0;
3182 pSMB->DataOffset = 0;
3183 pSMB->SetupCount = 4;
3184 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3185 pSMB->ParameterCount = pSMB->TotalParameterCount;
3186 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3187 pSMB->IsFsctl = 1; /* FSCTL */
3188 pSMB->IsRootFlag = 0;
3189 pSMB->Fid = fid; /* file handle always le */
3190 pSMB->ByteCount = 0;
3191
3192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3194 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003195 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003196 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 }
Steve French989c7e52009-05-02 05:32:20 +00003198
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003199 data_offset = le32_to_cpu(pSMBr->DataOffset);
3200 data_count = le32_to_cpu(pSMBr->DataCount);
3201 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3202 /* BB also check enough total bytes returned */
3203 rc = -EIO; /* bad smb */
3204 goto qreparse_out;
3205 }
3206 if (!data_count || (data_count > 2048)) {
3207 rc = -EIO;
3208 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3209 goto qreparse_out;
3210 }
3211 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003212 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003213 ((char *)&pSMBr->hdr.Protocol + data_offset);
3214 if ((char *)reparse_buf >= end_of_smb) {
3215 rc = -EIO;
3216 goto qreparse_out;
3217 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003218 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3219 cifs_dbg(FYI, "NFS style reparse tag\n");
3220 posix_buf = (struct reparse_posix_data *)reparse_buf;
3221
3222 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3223 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3224 le64_to_cpu(posix_buf->InodeType));
3225 rc = -EOPNOTSUPP;
3226 goto qreparse_out;
3227 }
3228 is_unicode = true;
3229 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3230 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3231 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3232 rc = -EIO;
3233 goto qreparse_out;
3234 }
3235 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3236 sub_len, is_unicode, nls_codepage);
3237 goto qreparse_out;
3238 } else if (reparse_buf->ReparseTag !=
3239 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3240 rc = -EOPNOTSUPP;
3241 goto qreparse_out;
3242 }
3243
3244 /* Reparse tag is NTFS symlink */
3245 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3246 reparse_buf->PathBuffer;
3247 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3248 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003249 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3250 rc = -EIO;
3251 goto qreparse_out;
3252 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003253 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3254 is_unicode = true;
3255 else
3256 is_unicode = false;
3257
3258 /* BB FIXME investigate remapping reserved chars here */
3259 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3260 nls_codepage);
3261 if (!*symlinkinfo)
3262 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003264 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003266 /*
3267 * Note: On -EAGAIN error only caller can retry on handle based calls
3268 * since file handle passed in no longer valid.
3269 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 return rc;
3271}
3272
Steve Frenchc7f508a2013-10-14 15:27:32 -05003273int
3274CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3275 __u16 fid)
3276{
3277 int rc = 0;
3278 int bytes_returned;
3279 struct smb_com_transaction_compr_ioctl_req *pSMB;
3280 struct smb_com_transaction_ioctl_rsp *pSMBr;
3281
3282 cifs_dbg(FYI, "Set compression for %u\n", fid);
3283 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3284 (void **) &pSMBr);
3285 if (rc)
3286 return rc;
3287
3288 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3289
3290 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003291 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003292 pSMB->MaxParameterCount = 0;
3293 pSMB->MaxDataCount = 0;
3294 pSMB->MaxSetupCount = 4;
3295 pSMB->Reserved = 0;
3296 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003297 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003298 pSMB->DataOffset =
3299 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3300 compression_state) - 4); /* 84 */
3301 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003302 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003303 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003304 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003305 pSMB->IsFsctl = 1; /* FSCTL */
3306 pSMB->IsRootFlag = 0;
3307 pSMB->Fid = fid; /* file handle always le */
3308 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003309 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003310 inc_rfc1001_len(pSMB, 5);
3311
3312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3314 if (rc)
3315 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3316
3317 cifs_buf_release(pSMB);
3318
3319 /*
3320 * Note: On -EAGAIN error only caller can retry on handle based calls
3321 * since file handle passed in no longer valid.
3322 */
3323 return rc;
3324}
3325
3326
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327#ifdef CONFIG_CIFS_POSIX
3328
3329/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003330static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003331 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332{
3333 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003334 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3335 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3336 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003337/*
3338 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3339 ace->e_perm, ace->e_tag, ace->e_id);
3340*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
3342 return;
3343}
3344
3345/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003346static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3347 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348{
3349 int size = 0;
3350 int i;
3351 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003352 struct cifs_posix_ace *pACE;
3353 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003354 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355
3356 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3357 return -EOPNOTSUPP;
3358
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003359 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 count = le16_to_cpu(cifs_acl->access_entry_count);
3361 pACE = &cifs_acl->ace_array[0];
3362 size = sizeof(struct cifs_posix_acl);
3363 size += sizeof(struct cifs_posix_ace) * count;
3364 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003365 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003366 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3367 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 return -EINVAL;
3369 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003370 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 count = le16_to_cpu(cifs_acl->access_entry_count);
3372 size = sizeof(struct cifs_posix_acl);
3373 size += sizeof(struct cifs_posix_ace) * count;
3374/* skip past access ACEs to get to default ACEs */
3375 pACE = &cifs_acl->ace_array[count];
3376 count = le16_to_cpu(cifs_acl->default_entry_count);
3377 size += sizeof(struct cifs_posix_ace) * count;
3378 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003379 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 return -EINVAL;
3381 } else {
3382 /* illegal type */
3383 return -EINVAL;
3384 }
3385
3386 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003387 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003388 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003389 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 return -ERANGE;
3391 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003392 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3393
Steve Frenchff7feac2005-11-15 16:45:16 -08003394 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003395 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003396 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003397 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 }
3399 }
3400 return size;
3401}
3402
Steve French50c2f752007-07-13 00:33:32 +00003403static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003404 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405{
3406 __u16 rc = 0; /* 0 = ACL converted ok */
3407
Steve Frenchff7feac2005-11-15 16:45:16 -08003408 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3409 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003411 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 /* Probably no need to le convert -1 on any arch but can not hurt */
3413 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003414 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003415 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003416/*
3417 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3418 ace->e_perm, ace->e_tag, ace->e_id);
3419*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 return rc;
3421}
3422
3423/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003424static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3425 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426{
3427 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003428 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003429 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003430 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 int count;
3432 int i;
3433
Steve French790fe572007-07-07 19:25:05 +00003434 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 return 0;
3436
3437 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003438 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3439 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003440 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003441 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3442 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 return 0;
3444 }
3445 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003446 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003447 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003448 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003449 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003450 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003451 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003452 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003453 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 return 0;
3455 }
Steve French50c2f752007-07-13 00:33:32 +00003456 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003457 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003458 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 /* ACE not converted */
3460 break;
3461 }
3462 }
Steve French790fe572007-07-07 19:25:05 +00003463 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3465 rc += sizeof(struct cifs_posix_acl);
3466 /* BB add check to make sure ACL does not overflow SMB */
3467 }
3468 return rc;
3469}
3470
3471int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003472CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003473 const unsigned char *searchName,
3474 char *acl_inf, const int buflen, const int acl_type,
3475 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476{
3477/* SMB_QUERY_POSIX_ACL */
3478 TRANSACTION2_QPI_REQ *pSMB = NULL;
3479 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3480 int rc = 0;
3481 int bytes_returned;
3482 int name_len;
3483 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003484
Joe Perchesf96637b2013-05-04 22:12:25 -05003485 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486
3487queryAclRetry:
3488 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3489 (void **) &pSMBr);
3490 if (rc)
3491 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003492
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3494 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003495 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3496 searchName, PATH_MAX, nls_codepage,
3497 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 name_len++; /* trailing null */
3499 name_len *= 2;
3500 pSMB->FileName[name_len] = 0;
3501 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003502 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 name_len = strnlen(searchName, PATH_MAX);
3504 name_len++; /* trailing null */
3505 strncpy(pSMB->FileName, searchName, name_len);
3506 }
3507
3508 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3509 pSMB->TotalDataCount = 0;
3510 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003511 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 pSMB->MaxDataCount = cpu_to_le16(4000);
3513 pSMB->MaxSetupCount = 0;
3514 pSMB->Reserved = 0;
3515 pSMB->Flags = 0;
3516 pSMB->Timeout = 0;
3517 pSMB->Reserved2 = 0;
3518 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003519 offsetof(struct smb_com_transaction2_qpi_req,
3520 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 pSMB->DataCount = 0;
3522 pSMB->DataOffset = 0;
3523 pSMB->SetupCount = 1;
3524 pSMB->Reserved3 = 0;
3525 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3526 byte_count = params + 1 /* pad */ ;
3527 pSMB->TotalParameterCount = cpu_to_le16(params);
3528 pSMB->ParameterCount = pSMB->TotalParameterCount;
3529 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3530 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003531 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 pSMB->ByteCount = cpu_to_le16(byte_count);
3533
3534 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3535 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003536 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003538 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 } else {
3540 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003541
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003544 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 rc = -EIO; /* bad smb */
3546 else {
3547 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3548 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3549 rc = cifs_copy_posix_acl(acl_inf,
3550 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003551 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 }
3553 }
3554 cifs_buf_release(pSMB);
3555 if (rc == -EAGAIN)
3556 goto queryAclRetry;
3557 return rc;
3558}
3559
3560int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003561CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003562 const unsigned char *fileName,
3563 const char *local_acl, const int buflen,
3564 const int acl_type,
3565 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566{
3567 struct smb_com_transaction2_spi_req *pSMB = NULL;
3568 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3569 char *parm_data;
3570 int name_len;
3571 int rc = 0;
3572 int bytes_returned = 0;
3573 __u16 params, byte_count, data_count, param_offset, offset;
3574
Joe Perchesf96637b2013-05-04 22:12:25 -05003575 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576setAclRetry:
3577 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003578 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 if (rc)
3580 return rc;
3581 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3582 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003583 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3584 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 name_len++; /* trailing null */
3586 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003587 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 name_len = strnlen(fileName, PATH_MAX);
3589 name_len++; /* trailing null */
3590 strncpy(pSMB->FileName, fileName, name_len);
3591 }
3592 params = 6 + name_len;
3593 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003594 /* BB find max SMB size from sess */
3595 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 pSMB->MaxSetupCount = 0;
3597 pSMB->Reserved = 0;
3598 pSMB->Flags = 0;
3599 pSMB->Timeout = 0;
3600 pSMB->Reserved2 = 0;
3601 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003602 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 offset = param_offset + params;
3604 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3605 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3606
3607 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003608 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609
Steve French790fe572007-07-07 19:25:05 +00003610 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 rc = -EOPNOTSUPP;
3612 goto setACLerrorExit;
3613 }
3614 pSMB->DataOffset = cpu_to_le16(offset);
3615 pSMB->SetupCount = 1;
3616 pSMB->Reserved3 = 0;
3617 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3618 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3619 byte_count = 3 /* pad */ + params + data_count;
3620 pSMB->DataCount = cpu_to_le16(data_count);
3621 pSMB->TotalDataCount = pSMB->DataCount;
3622 pSMB->ParameterCount = cpu_to_le16(params);
3623 pSMB->TotalParameterCount = pSMB->ParameterCount;
3624 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003625 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 pSMB->ByteCount = cpu_to_le16(byte_count);
3627 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003628 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003629 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003630 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631
3632setACLerrorExit:
3633 cifs_buf_release(pSMB);
3634 if (rc == -EAGAIN)
3635 goto setAclRetry;
3636 return rc;
3637}
3638
Steve Frenchf654bac2005-04-28 22:41:04 -07003639/* BB fix tabs in this function FIXME BB */
3640int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003641CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003642 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003643{
Steve French50c2f752007-07-13 00:33:32 +00003644 int rc = 0;
3645 struct smb_t2_qfi_req *pSMB = NULL;
3646 struct smb_t2_qfi_rsp *pSMBr = NULL;
3647 int bytes_returned;
3648 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003649
Joe Perchesf96637b2013-05-04 22:12:25 -05003650 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003651 if (tcon == NULL)
3652 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003653
3654GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003655 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3656 (void **) &pSMBr);
3657 if (rc)
3658 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003659
Steve Frenchad7a2922008-02-07 23:25:02 +00003660 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003661 pSMB->t2.TotalDataCount = 0;
3662 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3663 /* BB find exact max data count below from sess structure BB */
3664 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3665 pSMB->t2.MaxSetupCount = 0;
3666 pSMB->t2.Reserved = 0;
3667 pSMB->t2.Flags = 0;
3668 pSMB->t2.Timeout = 0;
3669 pSMB->t2.Reserved2 = 0;
3670 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3671 Fid) - 4);
3672 pSMB->t2.DataCount = 0;
3673 pSMB->t2.DataOffset = 0;
3674 pSMB->t2.SetupCount = 1;
3675 pSMB->t2.Reserved3 = 0;
3676 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3677 byte_count = params + 1 /* pad */ ;
3678 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3679 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3680 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3681 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003682 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003683 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003684 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003685
Steve French790fe572007-07-07 19:25:05 +00003686 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3688 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003689 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003690 } else {
3691 /* decode response */
3692 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003693 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003694 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003695 /* If rc should we check for EOPNOSUPP and
3696 disable the srvino flag? or in caller? */
3697 rc = -EIO; /* bad smb */
3698 else {
3699 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3700 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3701 struct file_chattr_info *pfinfo;
3702 /* BB Do we need a cast or hash here ? */
3703 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003704 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003705 rc = -EIO;
3706 goto GetExtAttrOut;
3707 }
3708 pfinfo = (struct file_chattr_info *)
3709 (data_offset + (char *) &pSMBr->hdr.Protocol);
3710 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003711 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003712 }
3713 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003714GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003715 cifs_buf_release(pSMB);
3716 if (rc == -EAGAIN)
3717 goto GetExtAttrRetry;
3718 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003719}
3720
Steve Frenchf654bac2005-04-28 22:41:04 -07003721#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
Jeff Layton79df1ba2010-12-06 12:52:08 -05003723#ifdef CONFIG_CIFS_ACL
3724/*
3725 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3726 * all NT TRANSACTS that we init here have total parm and data under about 400
3727 * bytes (to fit in small cifs buffer size), which is the case so far, it
3728 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3729 * returned setup area) and MaxParameterCount (returned parms size) must be set
3730 * by caller
3731 */
3732static int
3733smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003734 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003735 void **ret_buf)
3736{
3737 int rc;
3738 __u32 temp_offset;
3739 struct smb_com_ntransact_req *pSMB;
3740
3741 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3742 (void **)&pSMB);
3743 if (rc)
3744 return rc;
3745 *ret_buf = (void *)pSMB;
3746 pSMB->Reserved = 0;
3747 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3748 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003749 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003750 pSMB->ParameterCount = pSMB->TotalParameterCount;
3751 pSMB->DataCount = pSMB->TotalDataCount;
3752 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3753 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3754 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3755 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3756 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3757 pSMB->SubCommand = cpu_to_le16(sub_command);
3758 return 0;
3759}
3760
3761static int
3762validate_ntransact(char *buf, char **ppparm, char **ppdata,
3763 __u32 *pparmlen, __u32 *pdatalen)
3764{
3765 char *end_of_smb;
3766 __u32 data_count, data_offset, parm_count, parm_offset;
3767 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003768 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003769
3770 *pdatalen = 0;
3771 *pparmlen = 0;
3772
3773 if (buf == NULL)
3774 return -EINVAL;
3775
3776 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3777
Jeff Layton820a8032011-05-04 08:05:26 -04003778 bcc = get_bcc(&pSMBr->hdr);
3779 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003780 (char *)&pSMBr->ByteCount;
3781
3782 data_offset = le32_to_cpu(pSMBr->DataOffset);
3783 data_count = le32_to_cpu(pSMBr->DataCount);
3784 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3785 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3786
3787 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3788 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3789
3790 /* should we also check that parm and data areas do not overlap? */
3791 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003792 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003793 return -EINVAL;
3794 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003795 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003796 return -EINVAL;
3797 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003798 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003799 return -EINVAL;
3800 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003801 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3802 *ppdata, data_count, (data_count + *ppdata),
3803 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003804 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003805 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003806 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003807 return -EINVAL;
3808 }
3809 *pdatalen = data_count;
3810 *pparmlen = parm_count;
3811 return 0;
3812}
3813
Steve French0a4b92c2006-01-12 15:44:21 -08003814/* Get Security Descriptor (by handle) from remote server for a file or dir */
3815int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003816CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003817 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003818{
3819 int rc = 0;
3820 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003821 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003822 struct kvec iov[1];
3823
Joe Perchesf96637b2013-05-04 22:12:25 -05003824 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003825
Steve French630f3f0c2007-10-25 21:17:17 +00003826 *pbuflen = 0;
3827 *acl_inf = NULL;
3828
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003829 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003830 8 /* parm len */, tcon, (void **) &pSMB);
3831 if (rc)
3832 return rc;
3833
3834 pSMB->MaxParameterCount = cpu_to_le32(4);
3835 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3836 pSMB->MaxSetupCount = 0;
3837 pSMB->Fid = fid; /* file handle always le */
3838 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3839 CIFS_ACL_DACL);
3840 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003841 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003842 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003843 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003844
Steve Frencha761ac52007-10-18 21:45:27 +00003845 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003846 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003847 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003848 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003849 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003850 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003851 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003852 __u32 parm_len;
3853 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003854 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003855 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003856
3857/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003858 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003859 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003860 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003861 goto qsec_out;
3862 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3863
Joe Perchesf96637b2013-05-04 22:12:25 -05003864 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3865 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003866
3867 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3868 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003869 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003870 goto qsec_out;
3871 }
3872
3873/* BB check that data area is minimum length and as big as acl_len */
3874
Steve Frenchaf6f4612007-10-16 18:40:37 +00003875 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003876 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003877 cifs_dbg(VFS, "acl length %d does not match %d\n",
3878 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003879 if (*pbuflen > acl_len)
3880 *pbuflen = acl_len;
3881 }
Steve French0a4b92c2006-01-12 15:44:21 -08003882
Steve French630f3f0c2007-10-25 21:17:17 +00003883 /* check if buffer is big enough for the acl
3884 header followed by the smallest SID */
3885 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3886 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003887 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003888 rc = -EINVAL;
3889 *pbuflen = 0;
3890 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003891 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003892 if (*acl_inf == NULL) {
3893 *pbuflen = 0;
3894 rc = -ENOMEM;
3895 }
Steve French630f3f0c2007-10-25 21:17:17 +00003896 }
Steve French0a4b92c2006-01-12 15:44:21 -08003897 }
3898qsec_out:
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01003899 free_rsp_buf(buf_type, iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003900/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003901 return rc;
3902}
Steve French97837582007-12-31 07:47:21 +00003903
3904int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003905CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003906 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003907{
3908 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3909 int rc = 0;
3910 int bytes_returned = 0;
3911 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003912 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003913
3914setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003915 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003916 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003917 return rc;
Steve French97837582007-12-31 07:47:21 +00003918
3919 pSMB->MaxSetupCount = 0;
3920 pSMB->Reserved = 0;
3921
3922 param_count = 8;
3923 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3924 data_count = acllen;
3925 data_offset = param_offset + param_count;
3926 byte_count = 3 /* pad */ + param_count;
3927
3928 pSMB->DataCount = cpu_to_le32(data_count);
3929 pSMB->TotalDataCount = pSMB->DataCount;
3930 pSMB->MaxParameterCount = cpu_to_le32(4);
3931 pSMB->MaxDataCount = cpu_to_le32(16384);
3932 pSMB->ParameterCount = cpu_to_le32(param_count);
3933 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3934 pSMB->TotalParameterCount = pSMB->ParameterCount;
3935 pSMB->DataOffset = cpu_to_le32(data_offset);
3936 pSMB->SetupCount = 0;
3937 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3938 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3939
3940 pSMB->Fid = fid; /* file handle always le */
3941 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003942 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003943
3944 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003945 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3946 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003947 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003948 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003949 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003950
3951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3953
Joe Perchesf96637b2013-05-04 22:12:25 -05003954 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3955 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003956 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003957 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003958 cifs_buf_release(pSMB);
3959
3960 if (rc == -EAGAIN)
3961 goto setCifsAclRetry;
3962
3963 return (rc);
3964}
3965
Jeff Layton79df1ba2010-12-06 12:52:08 -05003966#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003967
Steve French6b8edfe2005-08-23 20:26:03 -07003968/* Legacy Query Path Information call for lookup to old servers such
3969 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003970int
3971SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3972 const char *search_name, FILE_ALL_INFO *data,
3973 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003974{
Steve Frenchad7a2922008-02-07 23:25:02 +00003975 QUERY_INFORMATION_REQ *pSMB;
3976 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003977 int rc = 0;
3978 int bytes_returned;
3979 int name_len;
3980
Joe Perchesf96637b2013-05-04 22:12:25 -05003981 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003982QInfRetry:
3983 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003984 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003985 if (rc)
3986 return rc;
3987
3988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3989 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003990 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003991 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003992 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003993 name_len++; /* trailing null */
3994 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003995 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003996 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003997 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003998 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003999 }
4000 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004001 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004002 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004003 pSMB->ByteCount = cpu_to_le16(name_len);
4004
4005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004007 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004008 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004009 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004010 struct timespec ts;
4011 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004012
4013 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004014 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004015 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004016 ts.tv_nsec = 0;
4017 ts.tv_sec = time;
4018 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004019 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4020 data->LastWriteTime = data->ChangeTime;
4021 data->LastAccessTime = 0;
4022 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004023 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004024 data->EndOfFile = data->AllocationSize;
4025 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004026 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004027 } else
4028 rc = -EIO; /* bad buffer passed in */
4029
4030 cifs_buf_release(pSMB);
4031
4032 if (rc == -EAGAIN)
4033 goto QInfRetry;
4034
4035 return rc;
4036}
4037
Jeff Laytonbcd53572010-02-12 07:44:16 -05004038int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004039CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004040 u16 netfid, FILE_ALL_INFO *pFindData)
4041{
4042 struct smb_t2_qfi_req *pSMB = NULL;
4043 struct smb_t2_qfi_rsp *pSMBr = NULL;
4044 int rc = 0;
4045 int bytes_returned;
4046 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004047
Jeff Laytonbcd53572010-02-12 07:44:16 -05004048QFileInfoRetry:
4049 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4050 (void **) &pSMBr);
4051 if (rc)
4052 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004053
Jeff Laytonbcd53572010-02-12 07:44:16 -05004054 params = 2 /* level */ + 2 /* fid */;
4055 pSMB->t2.TotalDataCount = 0;
4056 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4057 /* BB find exact max data count below from sess structure BB */
4058 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4059 pSMB->t2.MaxSetupCount = 0;
4060 pSMB->t2.Reserved = 0;
4061 pSMB->t2.Flags = 0;
4062 pSMB->t2.Timeout = 0;
4063 pSMB->t2.Reserved2 = 0;
4064 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4065 Fid) - 4);
4066 pSMB->t2.DataCount = 0;
4067 pSMB->t2.DataOffset = 0;
4068 pSMB->t2.SetupCount = 1;
4069 pSMB->t2.Reserved3 = 0;
4070 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4071 byte_count = params + 1 /* pad */ ;
4072 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4073 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4074 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4075 pSMB->Pad = 0;
4076 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004077 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004078 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004079
4080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4082 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004083 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004084 } else { /* decode response */
4085 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4086
4087 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4088 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004089 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004090 rc = -EIO; /* bad smb */
4091 else if (pFindData) {
4092 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4093 memcpy((char *) pFindData,
4094 (char *) &pSMBr->hdr.Protocol +
4095 data_offset, sizeof(FILE_ALL_INFO));
4096 } else
4097 rc = -ENOMEM;
4098 }
4099 cifs_buf_release(pSMB);
4100 if (rc == -EAGAIN)
4101 goto QFileInfoRetry;
4102
4103 return rc;
4104}
Steve French6b8edfe2005-08-23 20:26:03 -07004105
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004107CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004108 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004109 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004110 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004112 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 TRANSACTION2_QPI_REQ *pSMB = NULL;
4114 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4115 int rc = 0;
4116 int bytes_returned;
4117 int name_len;
4118 __u16 params, byte_count;
4119
Joe Perchesf96637b2013-05-04 22:12:25 -05004120 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121QPathInfoRetry:
4122 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4123 (void **) &pSMBr);
4124 if (rc)
4125 return rc;
4126
4127 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4128 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004129 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004130 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 name_len++; /* trailing null */
4132 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004133 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004134 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004136 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 }
4138
Steve French50c2f752007-07-13 00:33:32 +00004139 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 pSMB->TotalDataCount = 0;
4141 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004142 /* BB find exact max SMB PDU from sess structure BB */
4143 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 pSMB->MaxSetupCount = 0;
4145 pSMB->Reserved = 0;
4146 pSMB->Flags = 0;
4147 pSMB->Timeout = 0;
4148 pSMB->Reserved2 = 0;
4149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004150 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 pSMB->DataCount = 0;
4152 pSMB->DataOffset = 0;
4153 pSMB->SetupCount = 1;
4154 pSMB->Reserved3 = 0;
4155 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4156 byte_count = params + 1 /* pad */ ;
4157 pSMB->TotalParameterCount = cpu_to_le16(params);
4158 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004159 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004160 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4161 else
4162 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004164 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 pSMB->ByteCount = cpu_to_le16(byte_count);
4166
4167 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4168 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4169 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004170 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 } else { /* decode response */
4172 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4173
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004174 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4175 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004176 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004178 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004179 rc = -EIO; /* 24 or 26 expected but we do not read
4180 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004181 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004182 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004184
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004185 /*
4186 * On legacy responses we do not read the last field,
4187 * EAsize, fortunately since it varies by subdialect and
4188 * also note it differs on Set vs Get, ie two bytes or 4
4189 * bytes depending but we don't care here.
4190 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004191 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004192 size = sizeof(FILE_INFO_STANDARD);
4193 else
4194 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004195 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004196 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 } else
4198 rc = -ENOMEM;
4199 }
4200 cifs_buf_release(pSMB);
4201 if (rc == -EAGAIN)
4202 goto QPathInfoRetry;
4203
4204 return rc;
4205}
4206
4207int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004208CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004209 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4210{
4211 struct smb_t2_qfi_req *pSMB = NULL;
4212 struct smb_t2_qfi_rsp *pSMBr = NULL;
4213 int rc = 0;
4214 int bytes_returned;
4215 __u16 params, byte_count;
4216
4217UnixQFileInfoRetry:
4218 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4219 (void **) &pSMBr);
4220 if (rc)
4221 return rc;
4222
4223 params = 2 /* level */ + 2 /* fid */;
4224 pSMB->t2.TotalDataCount = 0;
4225 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4226 /* BB find exact max data count below from sess structure BB */
4227 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4228 pSMB->t2.MaxSetupCount = 0;
4229 pSMB->t2.Reserved = 0;
4230 pSMB->t2.Flags = 0;
4231 pSMB->t2.Timeout = 0;
4232 pSMB->t2.Reserved2 = 0;
4233 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4234 Fid) - 4);
4235 pSMB->t2.DataCount = 0;
4236 pSMB->t2.DataOffset = 0;
4237 pSMB->t2.SetupCount = 1;
4238 pSMB->t2.Reserved3 = 0;
4239 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4240 byte_count = params + 1 /* pad */ ;
4241 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4242 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4243 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4244 pSMB->Pad = 0;
4245 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004246 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004247 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004248
4249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4251 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004252 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004253 } else { /* decode response */
4254 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4255
Jeff Layton820a8032011-05-04 08:05:26 -04004256 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004257 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 -05004258 rc = -EIO; /* bad smb */
4259 } else {
4260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4261 memcpy((char *) pFindData,
4262 (char *) &pSMBr->hdr.Protocol +
4263 data_offset,
4264 sizeof(FILE_UNIX_BASIC_INFO));
4265 }
4266 }
4267
4268 cifs_buf_release(pSMB);
4269 if (rc == -EAGAIN)
4270 goto UnixQFileInfoRetry;
4271
4272 return rc;
4273}
4274
4275int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004276CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004278 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004279 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280{
4281/* SMB_QUERY_FILE_UNIX_BASIC */
4282 TRANSACTION2_QPI_REQ *pSMB = NULL;
4283 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4284 int rc = 0;
4285 int bytes_returned = 0;
4286 int name_len;
4287 __u16 params, byte_count;
4288
Joe Perchesf96637b2013-05-04 22:12:25 -05004289 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290UnixQPathInfoRetry:
4291 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4292 (void **) &pSMBr);
4293 if (rc)
4294 return rc;
4295
4296 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4297 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004298 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4299 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 name_len++; /* trailing null */
4301 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004302 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 name_len = strnlen(searchName, PATH_MAX);
4304 name_len++; /* trailing null */
4305 strncpy(pSMB->FileName, searchName, name_len);
4306 }
4307
Steve French50c2f752007-07-13 00:33:32 +00004308 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 pSMB->TotalDataCount = 0;
4310 pSMB->MaxParameterCount = cpu_to_le16(2);
4311 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004312 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 pSMB->MaxSetupCount = 0;
4314 pSMB->Reserved = 0;
4315 pSMB->Flags = 0;
4316 pSMB->Timeout = 0;
4317 pSMB->Reserved2 = 0;
4318 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004319 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 pSMB->DataCount = 0;
4321 pSMB->DataOffset = 0;
4322 pSMB->SetupCount = 1;
4323 pSMB->Reserved3 = 0;
4324 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4325 byte_count = params + 1 /* pad */ ;
4326 pSMB->TotalParameterCount = cpu_to_le16(params);
4327 pSMB->ParameterCount = pSMB->TotalParameterCount;
4328 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4329 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004330 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 pSMB->ByteCount = cpu_to_le16(byte_count);
4332
4333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4335 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004336 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 } else { /* decode response */
4338 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4339
Jeff Layton820a8032011-05-04 08:05:26 -04004340 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004341 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 -07004342 rc = -EIO; /* bad smb */
4343 } else {
4344 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4345 memcpy((char *) pFindData,
4346 (char *) &pSMBr->hdr.Protocol +
4347 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004348 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 }
4350 }
4351 cifs_buf_release(pSMB);
4352 if (rc == -EAGAIN)
4353 goto UnixQPathInfoRetry;
4354
4355 return rc;
4356}
4357
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358/* xid, tcon, searchName and codepage are input parms, rest are returned */
4359int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004360CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004361 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004362 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004363 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364{
4365/* level 257 SMB_ */
4366 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4367 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004368 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 int rc = 0;
4370 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004371 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004373 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
Joe Perchesf96637b2013-05-04 22:12:25 -05004375 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
4377findFirstRetry:
4378 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4379 (void **) &pSMBr);
4380 if (rc)
4381 return rc;
4382
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004383 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004384 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004385
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4387 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004388 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4389 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004390 /* We can not add the asterik earlier in case
4391 it got remapped to 0xF03A as if it were part of the
4392 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004394 if (msearch) {
4395 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4396 pSMB->FileName[name_len+1] = 0;
4397 pSMB->FileName[name_len+2] = '*';
4398 pSMB->FileName[name_len+3] = 0;
4399 name_len += 4; /* now the trailing null */
4400 /* null terminate just in case */
4401 pSMB->FileName[name_len] = 0;
4402 pSMB->FileName[name_len+1] = 0;
4403 name_len += 2;
4404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 } else { /* BB add check for overrun of SMB buf BB */
4406 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004408 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 free buffer exit; BB */
4410 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004411 if (msearch) {
4412 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4413 pSMB->FileName[name_len+1] = '*';
4414 pSMB->FileName[name_len+2] = 0;
4415 name_len += 3;
4416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 }
4418
4419 params = 12 + name_len /* includes null */ ;
4420 pSMB->TotalDataCount = 0; /* no EAs */
4421 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004422 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 pSMB->MaxSetupCount = 0;
4424 pSMB->Reserved = 0;
4425 pSMB->Flags = 0;
4426 pSMB->Timeout = 0;
4427 pSMB->Reserved2 = 0;
4428 byte_count = params + 1 /* pad */ ;
4429 pSMB->TotalParameterCount = cpu_to_le16(params);
4430 pSMB->ParameterCount = pSMB->TotalParameterCount;
4431 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004432 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4433 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 pSMB->DataCount = 0;
4435 pSMB->DataOffset = 0;
4436 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4437 pSMB->Reserved3 = 0;
4438 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4439 pSMB->SearchAttributes =
4440 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4441 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004442 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004443 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4445
4446 /* BB what should we set StorageType to? Does it matter? BB */
4447 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004448 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 pSMB->ByteCount = cpu_to_le16(byte_count);
4450
4451 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004453 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
Steve French88274812006-03-09 22:21:45 +00004455 if (rc) {/* BB add logic to retry regular search if Unix search
4456 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004458 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004459
Steve French88274812006-03-09 22:21:45 +00004460 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
4462 /* BB eventually could optimize out free and realloc of buf */
4463 /* for this case */
4464 if (rc == -EAGAIN)
4465 goto findFirstRetry;
4466 } else { /* decode response */
4467 /* BB remember to free buffer if error BB */
4468 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004469 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004470 unsigned int lnoff;
4471
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004473 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 else
Steve French4b18f2a2008-04-29 00:06:05 +00004475 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476
4477 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004478 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004479 psrch_inf->srch_entries_start =
4480 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4483 le16_to_cpu(pSMBr->t2.ParameterOffset));
4484
Steve French790fe572007-07-07 19:25:05 +00004485 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004486 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 else
Steve French4b18f2a2008-04-29 00:06:05 +00004488 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489
Steve French50c2f752007-07-13 00:33:32 +00004490 psrch_inf->entries_in_buffer =
4491 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004492 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004494 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004495 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004496 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004497 psrch_inf->last_entry = NULL;
4498 return rc;
4499 }
4500
Steve French0752f152008-10-07 20:03:33 +00004501 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004502 lnoff;
4503
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004504 if (pnetfid)
4505 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 } else {
4507 cifs_buf_release(pSMB);
4508 }
4509 }
4510
4511 return rc;
4512}
4513
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004514int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4515 __u16 searchHandle, __u16 search_flags,
4516 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517{
4518 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4519 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004520 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 char *response_data;
4522 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004523 int bytes_returned;
4524 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 __u16 params, byte_count;
4526
Joe Perchesf96637b2013-05-04 22:12:25 -05004527 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
Steve French4b18f2a2008-04-29 00:06:05 +00004529 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 return -ENOENT;
4531
4532 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4533 (void **) &pSMBr);
4534 if (rc)
4535 return rc;
4536
Steve French50c2f752007-07-13 00:33:32 +00004537 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 byte_count = 0;
4539 pSMB->TotalDataCount = 0; /* no EAs */
4540 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004541 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 pSMB->MaxSetupCount = 0;
4543 pSMB->Reserved = 0;
4544 pSMB->Flags = 0;
4545 pSMB->Timeout = 0;
4546 pSMB->Reserved2 = 0;
4547 pSMB->ParameterOffset = cpu_to_le16(
4548 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4549 pSMB->DataCount = 0;
4550 pSMB->DataOffset = 0;
4551 pSMB->SetupCount = 1;
4552 pSMB->Reserved3 = 0;
4553 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4554 pSMB->SearchHandle = searchHandle; /* always kept as le */
4555 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004556 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4558 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004559 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560
4561 name_len = psrch_inf->resume_name_len;
4562 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004563 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4565 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004566 /* 14 byte parm len above enough for 2 byte null terminator */
4567 pSMB->ResumeFileName[name_len] = 0;
4568 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 } else {
4570 rc = -EINVAL;
4571 goto FNext2_err_exit;
4572 }
4573 byte_count = params + 1 /* pad */ ;
4574 pSMB->TotalParameterCount = cpu_to_le16(params);
4575 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004576 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004578
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4580 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004581 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 if (rc) {
4583 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004584 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004585 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004586 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004588 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 } else { /* decode response */
4590 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004591
Steve French790fe572007-07-07 19:25:05 +00004592 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004593 unsigned int lnoff;
4594
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 /* BB fixme add lock for file (srch_info) struct here */
4596 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004597 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 else
Steve French4b18f2a2008-04-29 00:06:05 +00004599 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 response_data = (char *) &pSMBr->hdr.Protocol +
4601 le16_to_cpu(pSMBr->t2.ParameterOffset);
4602 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4603 response_data = (char *)&pSMBr->hdr.Protocol +
4604 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004605 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004606 cifs_small_buf_release(
4607 psrch_inf->ntwrk_buf_start);
4608 else
4609 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 psrch_inf->srch_entries_start = response_data;
4611 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004612 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004613 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004614 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 else
Steve French4b18f2a2008-04-29 00:06:05 +00004616 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004617 psrch_inf->entries_in_buffer =
4618 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 psrch_inf->index_of_last_entry +=
4620 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004621 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004622 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004623 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004624 psrch_inf->last_entry = NULL;
4625 return rc;
4626 } else
4627 psrch_inf->last_entry =
4628 psrch_inf->srch_entries_start + lnoff;
4629
Joe Perchesf96637b2013-05-04 22:12:25 -05004630/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4631 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632
4633 /* BB fixme add unlock here */
4634 }
4635
4636 }
4637
4638 /* BB On error, should we leave previous search buf (and count and
4639 last entry fields) intact or free the previous one? */
4640
4641 /* Note: On -EAGAIN error only caller can retry on handle based calls
4642 since file handle passed in no longer valid */
4643FNext2_err_exit:
4644 if (rc != 0)
4645 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 return rc;
4647}
4648
4649int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004650CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004651 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652{
4653 int rc = 0;
4654 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655
Joe Perchesf96637b2013-05-04 22:12:25 -05004656 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4658
4659 /* no sense returning error if session restarted
4660 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004661 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 return 0;
4663 if (rc)
4664 return rc;
4665
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 pSMB->FileID = searchHandle;
4667 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004668 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004669 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004670 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004671
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004672 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673
4674 /* Since session is dead, search handle closed on server already */
4675 if (rc == -EAGAIN)
4676 rc = 0;
4677
4678 return rc;
4679}
4680
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004682CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004683 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004684 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685{
4686 int rc = 0;
4687 TRANSACTION2_QPI_REQ *pSMB = NULL;
4688 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4689 int name_len, bytes_returned;
4690 __u16 params, byte_count;
4691
Joe Perchesf96637b2013-05-04 22:12:25 -05004692 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004693 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004694 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695
4696GetInodeNumberRetry:
4697 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004698 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 if (rc)
4700 return rc;
4701
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4703 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004704 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004705 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004706 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 name_len++; /* trailing null */
4708 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004709 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004710 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004712 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 }
4714
4715 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4716 pSMB->TotalDataCount = 0;
4717 pSMB->MaxParameterCount = cpu_to_le16(2);
4718 /* BB find exact max data count below from sess structure BB */
4719 pSMB->MaxDataCount = cpu_to_le16(4000);
4720 pSMB->MaxSetupCount = 0;
4721 pSMB->Reserved = 0;
4722 pSMB->Flags = 0;
4723 pSMB->Timeout = 0;
4724 pSMB->Reserved2 = 0;
4725 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004726 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 pSMB->DataCount = 0;
4728 pSMB->DataOffset = 0;
4729 pSMB->SetupCount = 1;
4730 pSMB->Reserved3 = 0;
4731 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4732 byte_count = params + 1 /* pad */ ;
4733 pSMB->TotalParameterCount = cpu_to_le16(params);
4734 pSMB->ParameterCount = pSMB->TotalParameterCount;
4735 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4736 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004737 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 pSMB->ByteCount = cpu_to_le16(byte_count);
4739
4740 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4741 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4742 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004743 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 } else {
4745 /* decode response */
4746 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004748 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 /* If rc should we check for EOPNOSUPP and
4750 disable the srvino flag? or in caller? */
4751 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004752 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4754 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004755 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004757 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004758 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 rc = -EIO;
4760 goto GetInodeNumOut;
4761 }
4762 pfinfo = (struct file_internal_info *)
4763 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004764 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 }
4766 }
4767GetInodeNumOut:
4768 cifs_buf_release(pSMB);
4769 if (rc == -EAGAIN)
4770 goto GetInodeNumberRetry;
4771 return rc;
4772}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Igor Mammedovfec45852008-05-16 13:06:30 +04004774/* parses DFS refferal V3 structure
4775 * caller is responsible for freeing target_nodes
4776 * returns:
4777 * on success - 0
4778 * on failure - errno
4779 */
4780static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004781parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004782 unsigned int *num_of_nodes,
4783 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004784 const struct nls_table *nls_codepage, int remap,
4785 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004786{
4787 int i, rc = 0;
4788 char *data_end;
4789 bool is_unicode;
4790 struct dfs_referral_level_3 *ref;
4791
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004792 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4793 is_unicode = true;
4794 else
4795 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004796 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4797
4798 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004799 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4800 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004801 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004802 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004803 }
4804
4805 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004806 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004807 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4808 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004809 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004810 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004811 }
4812
4813 /* get the upper boundary of the resp buffer */
4814 data_end = (char *)(&(pSMBr->PathConsumed)) +
4815 le16_to_cpu(pSMBr->t2.DataCount);
4816
Joe Perchesf96637b2013-05-04 22:12:25 -05004817 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4818 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004819
Joe Perchesf96637b2013-05-04 22:12:25 -05004820 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4821 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004822 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004823 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004824 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004825 }
4826
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004827 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004828 for (i = 0; i < *num_of_nodes; i++) {
4829 char *temp;
4830 int max_len;
4831 struct dfs_info3_param *node = (*target_nodes)+i;
4832
Steve French0e0d2cf2009-05-01 05:27:32 +00004833 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004834 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004835 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4836 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004837 if (tmp == NULL) {
4838 rc = -ENOMEM;
4839 goto parse_DFS_referrals_exit;
4840 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004841 cifsConvertToUTF16((__le16 *) tmp, searchName,
4842 PATH_MAX, nls_codepage, remap);
4843 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004844 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004845 nls_codepage);
4846 kfree(tmp);
4847 } else
4848 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4849
Igor Mammedovfec45852008-05-16 13:06:30 +04004850 node->server_type = le16_to_cpu(ref->ServerType);
4851 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4852
4853 /* copy DfsPath */
4854 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4855 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004856 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4857 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004858 if (!node->path_name) {
4859 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004860 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004861 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004862
4863 /* copy link target UNC */
4864 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4865 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004866 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4867 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004868 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004869 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004870 goto parse_DFS_referrals_exit;
4871 }
4872
4873 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004874 }
4875
Steve Frencha1fe78f2008-05-16 18:48:38 +00004876parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004877 if (rc) {
4878 free_dfs_info_array(*target_nodes, *num_of_nodes);
4879 *target_nodes = NULL;
4880 *num_of_nodes = 0;
4881 }
4882 return rc;
4883}
4884
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004886CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004887 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004888 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004889 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890{
4891/* TRANS2_GET_DFS_REFERRAL */
4892 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4893 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 int rc = 0;
4895 int bytes_returned;
4896 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004898 *num_of_nodes = 0;
4899 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900
Joe Perchesf96637b2013-05-04 22:12:25 -05004901 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 if (ses == NULL)
4903 return -ENODEV;
4904getDFSRetry:
4905 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4906 (void **) &pSMBr);
4907 if (rc)
4908 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004909
4910 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004911 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004912 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 pSMB->hdr.Tid = ses->ipc_tid;
4914 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004915 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004917 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919
4920 if (ses->capabilities & CAP_UNICODE) {
4921 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4922 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004923 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004924 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004925 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 name_len++; /* trailing null */
4927 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004928 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004929 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004931 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 }
4933
Dan Carpenter65c3b202015-04-30 17:30:24 +03004934 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004935 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004936
Steve French50c2f752007-07-13 00:33:32 +00004937 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004938
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 params = 2 /* level */ + name_len /*includes null */ ;
4940 pSMB->TotalDataCount = 0;
4941 pSMB->DataCount = 0;
4942 pSMB->DataOffset = 0;
4943 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004944 /* BB find exact max SMB PDU from sess structure BB */
4945 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 pSMB->MaxSetupCount = 0;
4947 pSMB->Reserved = 0;
4948 pSMB->Flags = 0;
4949 pSMB->Timeout = 0;
4950 pSMB->Reserved2 = 0;
4951 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004952 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 pSMB->SetupCount = 1;
4954 pSMB->Reserved3 = 0;
4955 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4956 byte_count = params + 3 /* pad */ ;
4957 pSMB->ParameterCount = cpu_to_le16(params);
4958 pSMB->TotalParameterCount = pSMB->ParameterCount;
4959 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004960 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 pSMB->ByteCount = cpu_to_le16(byte_count);
4962
4963 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4965 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004966 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004967 goto GetDFSRefExit;
4968 }
4969 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004971 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004972 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004973 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004974 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004976
Joe Perchesf96637b2013-05-04 22:12:25 -05004977 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4978 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004979
4980 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004981 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004982 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004983 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004984
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004986 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987
4988 if (rc == -EAGAIN)
4989 goto getDFSRetry;
4990
4991 return rc;
4992}
4993
Steve French20962432005-09-21 22:05:57 -07004994/* Query File System Info such as free space to old servers such as Win 9x */
4995int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004996SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4997 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004998{
4999/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5000 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5001 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5002 FILE_SYSTEM_ALLOC_INFO *response_data;
5003 int rc = 0;
5004 int bytes_returned = 0;
5005 __u16 params, byte_count;
5006
Joe Perchesf96637b2013-05-04 22:12:25 -05005007 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005008oldQFSInfoRetry:
5009 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5010 (void **) &pSMBr);
5011 if (rc)
5012 return rc;
Steve French20962432005-09-21 22:05:57 -07005013
5014 params = 2; /* level */
5015 pSMB->TotalDataCount = 0;
5016 pSMB->MaxParameterCount = cpu_to_le16(2);
5017 pSMB->MaxDataCount = cpu_to_le16(1000);
5018 pSMB->MaxSetupCount = 0;
5019 pSMB->Reserved = 0;
5020 pSMB->Flags = 0;
5021 pSMB->Timeout = 0;
5022 pSMB->Reserved2 = 0;
5023 byte_count = params + 1 /* pad */ ;
5024 pSMB->TotalParameterCount = cpu_to_le16(params);
5025 pSMB->ParameterCount = pSMB->TotalParameterCount;
5026 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5027 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5028 pSMB->DataCount = 0;
5029 pSMB->DataOffset = 0;
5030 pSMB->SetupCount = 1;
5031 pSMB->Reserved3 = 0;
5032 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5033 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005034 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005035 pSMB->ByteCount = cpu_to_le16(byte_count);
5036
5037 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5038 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5039 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005040 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005041 } else { /* decode response */
5042 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5043
Jeff Layton820a8032011-05-04 08:05:26 -04005044 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005045 rc = -EIO; /* bad smb */
5046 else {
5047 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005048 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005049 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005050
Steve French50c2f752007-07-13 00:33:32 +00005051 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005052 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5053 FSData->f_bsize =
5054 le16_to_cpu(response_data->BytesPerSector) *
5055 le32_to_cpu(response_data->
5056 SectorsPerAllocationUnit);
5057 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005058 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005059 FSData->f_bfree = FSData->f_bavail =
5060 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005061 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5062 (unsigned long long)FSData->f_blocks,
5063 (unsigned long long)FSData->f_bfree,
5064 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005065 }
5066 }
5067 cifs_buf_release(pSMB);
5068
5069 if (rc == -EAGAIN)
5070 goto oldQFSInfoRetry;
5071
5072 return rc;
5073}
5074
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005076CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5077 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078{
5079/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5080 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5081 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5082 FILE_SYSTEM_INFO *response_data;
5083 int rc = 0;
5084 int bytes_returned = 0;
5085 __u16 params, byte_count;
5086
Joe Perchesf96637b2013-05-04 22:12:25 -05005087 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088QFSInfoRetry:
5089 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5090 (void **) &pSMBr);
5091 if (rc)
5092 return rc;
5093
5094 params = 2; /* level */
5095 pSMB->TotalDataCount = 0;
5096 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005097 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 pSMB->MaxSetupCount = 0;
5099 pSMB->Reserved = 0;
5100 pSMB->Flags = 0;
5101 pSMB->Timeout = 0;
5102 pSMB->Reserved2 = 0;
5103 byte_count = params + 1 /* pad */ ;
5104 pSMB->TotalParameterCount = cpu_to_le16(params);
5105 pSMB->ParameterCount = pSMB->TotalParameterCount;
5106 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005107 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 pSMB->DataCount = 0;
5109 pSMB->DataOffset = 0;
5110 pSMB->SetupCount = 1;
5111 pSMB->Reserved3 = 0;
5112 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5113 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005114 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 pSMB->ByteCount = cpu_to_le16(byte_count);
5116
5117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5119 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005120 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005122 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123
Jeff Layton820a8032011-05-04 08:05:26 -04005124 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 rc = -EIO; /* bad smb */
5126 else {
5127 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128
5129 response_data =
5130 (FILE_SYSTEM_INFO
5131 *) (((char *) &pSMBr->hdr.Protocol) +
5132 data_offset);
5133 FSData->f_bsize =
5134 le32_to_cpu(response_data->BytesPerSector) *
5135 le32_to_cpu(response_data->
5136 SectorsPerAllocationUnit);
5137 FSData->f_blocks =
5138 le64_to_cpu(response_data->TotalAllocationUnits);
5139 FSData->f_bfree = FSData->f_bavail =
5140 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005141 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5142 (unsigned long long)FSData->f_blocks,
5143 (unsigned long long)FSData->f_bfree,
5144 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 }
5146 }
5147 cifs_buf_release(pSMB);
5148
5149 if (rc == -EAGAIN)
5150 goto QFSInfoRetry;
5151
5152 return rc;
5153}
5154
5155int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005156CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157{
5158/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5159 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5160 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5161 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5162 int rc = 0;
5163 int bytes_returned = 0;
5164 __u16 params, byte_count;
5165
Joe Perchesf96637b2013-05-04 22:12:25 -05005166 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167QFSAttributeRetry:
5168 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5169 (void **) &pSMBr);
5170 if (rc)
5171 return rc;
5172
5173 params = 2; /* level */
5174 pSMB->TotalDataCount = 0;
5175 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005176 /* BB find exact max SMB PDU from sess structure BB */
5177 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 pSMB->MaxSetupCount = 0;
5179 pSMB->Reserved = 0;
5180 pSMB->Flags = 0;
5181 pSMB->Timeout = 0;
5182 pSMB->Reserved2 = 0;
5183 byte_count = params + 1 /* pad */ ;
5184 pSMB->TotalParameterCount = cpu_to_le16(params);
5185 pSMB->ParameterCount = pSMB->TotalParameterCount;
5186 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005187 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 pSMB->DataCount = 0;
5189 pSMB->DataOffset = 0;
5190 pSMB->SetupCount = 1;
5191 pSMB->Reserved3 = 0;
5192 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5193 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005194 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 pSMB->ByteCount = cpu_to_le16(byte_count);
5196
5197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5199 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005200 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 } else { /* decode response */
5202 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5203
Jeff Layton820a8032011-05-04 08:05:26 -04005204 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005205 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 rc = -EIO; /* bad smb */
5207 } else {
5208 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5209 response_data =
5210 (FILE_SYSTEM_ATTRIBUTE_INFO
5211 *) (((char *) &pSMBr->hdr.Protocol) +
5212 data_offset);
5213 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005214 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 }
5216 }
5217 cifs_buf_release(pSMB);
5218
5219 if (rc == -EAGAIN)
5220 goto QFSAttributeRetry;
5221
5222 return rc;
5223}
5224
5225int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005226CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227{
5228/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5229 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5230 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5231 FILE_SYSTEM_DEVICE_INFO *response_data;
5232 int rc = 0;
5233 int bytes_returned = 0;
5234 __u16 params, byte_count;
5235
Joe Perchesf96637b2013-05-04 22:12:25 -05005236 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237QFSDeviceRetry:
5238 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5239 (void **) &pSMBr);
5240 if (rc)
5241 return rc;
5242
5243 params = 2; /* level */
5244 pSMB->TotalDataCount = 0;
5245 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005246 /* BB find exact max SMB PDU from sess structure BB */
5247 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 pSMB->MaxSetupCount = 0;
5249 pSMB->Reserved = 0;
5250 pSMB->Flags = 0;
5251 pSMB->Timeout = 0;
5252 pSMB->Reserved2 = 0;
5253 byte_count = params + 1 /* pad */ ;
5254 pSMB->TotalParameterCount = cpu_to_le16(params);
5255 pSMB->ParameterCount = pSMB->TotalParameterCount;
5256 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005257 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258
5259 pSMB->DataCount = 0;
5260 pSMB->DataOffset = 0;
5261 pSMB->SetupCount = 1;
5262 pSMB->Reserved3 = 0;
5263 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5264 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005265 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 pSMB->ByteCount = cpu_to_le16(byte_count);
5267
5268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5269 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5270 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005271 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 } else { /* decode response */
5273 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5274
Jeff Layton820a8032011-05-04 08:05:26 -04005275 if (rc || get_bcc(&pSMBr->hdr) <
5276 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 rc = -EIO; /* bad smb */
5278 else {
5279 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5280 response_data =
Steve French737b7582005-04-28 22:41:06 -07005281 (FILE_SYSTEM_DEVICE_INFO *)
5282 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 data_offset);
5284 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005285 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 }
5287 }
5288 cifs_buf_release(pSMB);
5289
5290 if (rc == -EAGAIN)
5291 goto QFSDeviceRetry;
5292
5293 return rc;
5294}
5295
5296int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005297CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298{
5299/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5300 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5301 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5302 FILE_SYSTEM_UNIX_INFO *response_data;
5303 int rc = 0;
5304 int bytes_returned = 0;
5305 __u16 params, byte_count;
5306
Joe Perchesf96637b2013-05-04 22:12:25 -05005307 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005309 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5310 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 if (rc)
5312 return rc;
5313
5314 params = 2; /* level */
5315 pSMB->TotalDataCount = 0;
5316 pSMB->DataCount = 0;
5317 pSMB->DataOffset = 0;
5318 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005319 /* BB find exact max SMB PDU from sess structure BB */
5320 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 pSMB->MaxSetupCount = 0;
5322 pSMB->Reserved = 0;
5323 pSMB->Flags = 0;
5324 pSMB->Timeout = 0;
5325 pSMB->Reserved2 = 0;
5326 byte_count = params + 1 /* pad */ ;
5327 pSMB->ParameterCount = cpu_to_le16(params);
5328 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005329 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5330 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 pSMB->SetupCount = 1;
5332 pSMB->Reserved3 = 0;
5333 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5334 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005335 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 pSMB->ByteCount = cpu_to_le16(byte_count);
5337
5338 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5339 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5340 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005341 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 } else { /* decode response */
5343 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5344
Jeff Layton820a8032011-05-04 08:05:26 -04005345 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 rc = -EIO; /* bad smb */
5347 } else {
5348 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5349 response_data =
5350 (FILE_SYSTEM_UNIX_INFO
5351 *) (((char *) &pSMBr->hdr.Protocol) +
5352 data_offset);
5353 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005354 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 }
5356 }
5357 cifs_buf_release(pSMB);
5358
5359 if (rc == -EAGAIN)
5360 goto QFSUnixRetry;
5361
5362
5363 return rc;
5364}
5365
Jeremy Allisonac670552005-06-22 17:26:35 -07005366int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005367CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005368{
5369/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5370 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5371 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5372 int rc = 0;
5373 int bytes_returned = 0;
5374 __u16 params, param_offset, offset, byte_count;
5375
Joe Perchesf96637b2013-05-04 22:12:25 -05005376 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005377SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005378 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005379 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5380 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005381 if (rc)
5382 return rc;
5383
5384 params = 4; /* 2 bytes zero followed by info level. */
5385 pSMB->MaxSetupCount = 0;
5386 pSMB->Reserved = 0;
5387 pSMB->Flags = 0;
5388 pSMB->Timeout = 0;
5389 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005390 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5391 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005392 offset = param_offset + params;
5393
5394 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005395 /* BB find exact max SMB PDU from sess structure BB */
5396 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005397 pSMB->SetupCount = 1;
5398 pSMB->Reserved3 = 0;
5399 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5400 byte_count = 1 /* pad */ + params + 12;
5401
5402 pSMB->DataCount = cpu_to_le16(12);
5403 pSMB->ParameterCount = cpu_to_le16(params);
5404 pSMB->TotalDataCount = pSMB->DataCount;
5405 pSMB->TotalParameterCount = pSMB->ParameterCount;
5406 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5407 pSMB->DataOffset = cpu_to_le16(offset);
5408
5409 /* Params. */
5410 pSMB->FileNum = 0;
5411 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5412
5413 /* Data. */
5414 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5415 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5416 pSMB->ClientUnixCap = cpu_to_le64(cap);
5417
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005418 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005419 pSMB->ByteCount = cpu_to_le16(byte_count);
5420
5421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5423 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005424 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005425 } else { /* decode response */
5426 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005427 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005428 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005429 }
5430 cifs_buf_release(pSMB);
5431
5432 if (rc == -EAGAIN)
5433 goto SETFSUnixRetry;
5434
5435 return rc;
5436}
5437
5438
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439
5440int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005441CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005442 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443{
5444/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5445 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5446 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5447 FILE_SYSTEM_POSIX_INFO *response_data;
5448 int rc = 0;
5449 int bytes_returned = 0;
5450 __u16 params, byte_count;
5451
Joe Perchesf96637b2013-05-04 22:12:25 -05005452 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453QFSPosixRetry:
5454 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5455 (void **) &pSMBr);
5456 if (rc)
5457 return rc;
5458
5459 params = 2; /* level */
5460 pSMB->TotalDataCount = 0;
5461 pSMB->DataCount = 0;
5462 pSMB->DataOffset = 0;
5463 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005464 /* BB find exact max SMB PDU from sess structure BB */
5465 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 pSMB->MaxSetupCount = 0;
5467 pSMB->Reserved = 0;
5468 pSMB->Flags = 0;
5469 pSMB->Timeout = 0;
5470 pSMB->Reserved2 = 0;
5471 byte_count = params + 1 /* pad */ ;
5472 pSMB->ParameterCount = cpu_to_le16(params);
5473 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005474 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5475 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 pSMB->SetupCount = 1;
5477 pSMB->Reserved3 = 0;
5478 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5479 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005480 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 pSMB->ByteCount = cpu_to_le16(byte_count);
5482
5483 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5484 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5485 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005486 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 } else { /* decode response */
5488 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5489
Jeff Layton820a8032011-05-04 08:05:26 -04005490 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 rc = -EIO; /* bad smb */
5492 } else {
5493 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5494 response_data =
5495 (FILE_SYSTEM_POSIX_INFO
5496 *) (((char *) &pSMBr->hdr.Protocol) +
5497 data_offset);
5498 FSData->f_bsize =
5499 le32_to_cpu(response_data->BlockSize);
5500 FSData->f_blocks =
5501 le64_to_cpu(response_data->TotalBlocks);
5502 FSData->f_bfree =
5503 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005504 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 FSData->f_bavail = FSData->f_bfree;
5506 } else {
5507 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005508 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 }
Steve French790fe572007-07-07 19:25:05 +00005510 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005512 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005513 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005515 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 }
5517 }
5518 cifs_buf_release(pSMB);
5519
5520 if (rc == -EAGAIN)
5521 goto QFSPosixRetry;
5522
5523 return rc;
5524}
5525
5526
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005527/*
5528 * We can not use write of zero bytes trick to set file size due to need for
5529 * large file support. Also note that this SetPathInfo is preferred to
5530 * SetFileInfo based method in next routine which is only needed to work around
5531 * a sharing violation bugin Samba which this routine can run into.
5532 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005534CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005535 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5536 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537{
5538 struct smb_com_transaction2_spi_req *pSMB = NULL;
5539 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5540 struct file_end_of_file_info *parm_data;
5541 int name_len;
5542 int rc = 0;
5543 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005544 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005545
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 __u16 params, byte_count, data_count, param_offset, offset;
5547
Joe Perchesf96637b2013-05-04 22:12:25 -05005548 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549SetEOFRetry:
5550 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5551 (void **) &pSMBr);
5552 if (rc)
5553 return rc;
5554
5555 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5556 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005557 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5558 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 name_len++; /* trailing null */
5560 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005561 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005562 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005564 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 }
5566 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005567 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005569 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 pSMB->MaxSetupCount = 0;
5571 pSMB->Reserved = 0;
5572 pSMB->Flags = 0;
5573 pSMB->Timeout = 0;
5574 pSMB->Reserved2 = 0;
5575 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005576 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005578 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005579 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5580 pSMB->InformationLevel =
5581 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5582 else
5583 pSMB->InformationLevel =
5584 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5585 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5587 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005588 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 else
5590 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005591 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 }
5593
5594 parm_data =
5595 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5596 offset);
5597 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5598 pSMB->DataOffset = cpu_to_le16(offset);
5599 pSMB->SetupCount = 1;
5600 pSMB->Reserved3 = 0;
5601 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5602 byte_count = 3 /* pad */ + params + data_count;
5603 pSMB->DataCount = cpu_to_le16(data_count);
5604 pSMB->TotalDataCount = pSMB->DataCount;
5605 pSMB->ParameterCount = cpu_to_le16(params);
5606 pSMB->TotalParameterCount = pSMB->ParameterCount;
5607 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005608 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 parm_data->FileSize = cpu_to_le64(size);
5610 pSMB->ByteCount = cpu_to_le16(byte_count);
5611 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5612 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005613 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005614 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615
5616 cifs_buf_release(pSMB);
5617
5618 if (rc == -EAGAIN)
5619 goto SetEOFRetry;
5620
5621 return rc;
5622}
5623
5624int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005625CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5626 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627{
5628 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 struct file_end_of_file_info *parm_data;
5630 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 __u16 params, param_offset, offset, byte_count, count;
5632
Joe Perchesf96637b2013-05-04 22:12:25 -05005633 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5634 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005635 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5636
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 if (rc)
5638 return rc;
5639
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005640 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5641 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005642
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 params = 6;
5644 pSMB->MaxSetupCount = 0;
5645 pSMB->Reserved = 0;
5646 pSMB->Flags = 0;
5647 pSMB->Timeout = 0;
5648 pSMB->Reserved2 = 0;
5649 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5650 offset = param_offset + params;
5651
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 count = sizeof(struct file_end_of_file_info);
5653 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005654 /* BB find exact max SMB PDU from sess structure BB */
5655 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 pSMB->SetupCount = 1;
5657 pSMB->Reserved3 = 0;
5658 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5659 byte_count = 3 /* pad */ + params + count;
5660 pSMB->DataCount = cpu_to_le16(count);
5661 pSMB->ParameterCount = cpu_to_le16(params);
5662 pSMB->TotalDataCount = pSMB->DataCount;
5663 pSMB->TotalParameterCount = pSMB->ParameterCount;
5664 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5665 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005666 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5667 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 pSMB->DataOffset = cpu_to_le16(offset);
5669 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005670 pSMB->Fid = cfile->fid.netfid;
5671 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5673 pSMB->InformationLevel =
5674 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5675 else
5676 pSMB->InformationLevel =
5677 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005678 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5680 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005681 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 else
5683 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005684 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 }
5686 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005687 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005689 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005691 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5692 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 }
5694
Steve French50c2f752007-07-13 00:33:32 +00005695 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 since file handle passed in no longer valid */
5697
5698 return rc;
5699}
5700
Steve French50c2f752007-07-13 00:33:32 +00005701/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702 an open handle, rather than by pathname - this is awkward due to
5703 potential access conflicts on the open, but it is unavoidable for these
5704 old servers since the only other choice is to go from 100 nanosecond DCE
5705 time and resort to the original setpathinfo level which takes the ancient
5706 DOS time format with 2 second granularity */
5707int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005708CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005709 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710{
5711 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712 char *data_offset;
5713 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 __u16 params, param_offset, offset, byte_count, count;
5715
Joe Perchesf96637b2013-05-04 22:12:25 -05005716 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005717 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5718
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 if (rc)
5720 return rc;
5721
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005722 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5723 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005724
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725 params = 6;
5726 pSMB->MaxSetupCount = 0;
5727 pSMB->Reserved = 0;
5728 pSMB->Flags = 0;
5729 pSMB->Timeout = 0;
5730 pSMB->Reserved2 = 0;
5731 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5732 offset = param_offset + params;
5733
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005734 data_offset = (char *)pSMB +
5735 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736
Steve French26f57362007-08-30 22:09:15 +00005737 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005739 /* BB find max SMB PDU from sess */
5740 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 pSMB->SetupCount = 1;
5742 pSMB->Reserved3 = 0;
5743 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5744 byte_count = 3 /* pad */ + params + count;
5745 pSMB->DataCount = cpu_to_le16(count);
5746 pSMB->ParameterCount = cpu_to_le16(params);
5747 pSMB->TotalDataCount = pSMB->DataCount;
5748 pSMB->TotalParameterCount = pSMB->ParameterCount;
5749 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5750 pSMB->DataOffset = cpu_to_le16(offset);
5751 pSMB->Fid = fid;
5752 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5753 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5754 else
5755 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5756 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005757 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005759 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005760 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005761 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005762 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5763 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764
Steve French50c2f752007-07-13 00:33:32 +00005765 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 since file handle passed in no longer valid */
5767
5768 return rc;
5769}
5770
Jeff Layton6d22f092008-09-23 11:48:35 -04005771int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005772CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005773 bool delete_file, __u16 fid, __u32 pid_of_opener)
5774{
5775 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5776 char *data_offset;
5777 int rc = 0;
5778 __u16 params, param_offset, offset, byte_count, count;
5779
Joe Perchesf96637b2013-05-04 22:12:25 -05005780 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005781 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5782
5783 if (rc)
5784 return rc;
5785
5786 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5787 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5788
5789 params = 6;
5790 pSMB->MaxSetupCount = 0;
5791 pSMB->Reserved = 0;
5792 pSMB->Flags = 0;
5793 pSMB->Timeout = 0;
5794 pSMB->Reserved2 = 0;
5795 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5796 offset = param_offset + params;
5797
5798 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5799
5800 count = 1;
5801 pSMB->MaxParameterCount = cpu_to_le16(2);
5802 /* BB find max SMB PDU from sess */
5803 pSMB->MaxDataCount = cpu_to_le16(1000);
5804 pSMB->SetupCount = 1;
5805 pSMB->Reserved3 = 0;
5806 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5807 byte_count = 3 /* pad */ + params + count;
5808 pSMB->DataCount = cpu_to_le16(count);
5809 pSMB->ParameterCount = cpu_to_le16(params);
5810 pSMB->TotalDataCount = pSMB->DataCount;
5811 pSMB->TotalParameterCount = pSMB->ParameterCount;
5812 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5813 pSMB->DataOffset = cpu_to_le16(offset);
5814 pSMB->Fid = fid;
5815 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5816 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005817 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005818 pSMB->ByteCount = cpu_to_le16(byte_count);
5819 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005820 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005821 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005822 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005823
5824 return rc;
5825}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826
5827int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005828CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005829 const char *fileName, const FILE_BASIC_INFO *data,
5830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831{
5832 TRANSACTION2_SPI_REQ *pSMB = NULL;
5833 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5834 int name_len;
5835 int rc = 0;
5836 int bytes_returned = 0;
5837 char *data_offset;
5838 __u16 params, param_offset, offset, byte_count, count;
5839
Joe Perchesf96637b2013-05-04 22:12:25 -05005840 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841
5842SetTimesRetry:
5843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5844 (void **) &pSMBr);
5845 if (rc)
5846 return rc;
5847
5848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5849 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005850 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5851 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852 name_len++; /* trailing null */
5853 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005854 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855 name_len = strnlen(fileName, PATH_MAX);
5856 name_len++; /* trailing null */
5857 strncpy(pSMB->FileName, fileName, name_len);
5858 }
5859
5860 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005861 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005863 /* BB find max SMB PDU from sess structure BB */
5864 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865 pSMB->MaxSetupCount = 0;
5866 pSMB->Reserved = 0;
5867 pSMB->Flags = 0;
5868 pSMB->Timeout = 0;
5869 pSMB->Reserved2 = 0;
5870 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005871 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 offset = param_offset + params;
5873 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5874 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5875 pSMB->DataOffset = cpu_to_le16(offset);
5876 pSMB->SetupCount = 1;
5877 pSMB->Reserved3 = 0;
5878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5879 byte_count = 3 /* pad */ + params + count;
5880
5881 pSMB->DataCount = cpu_to_le16(count);
5882 pSMB->ParameterCount = cpu_to_le16(params);
5883 pSMB->TotalDataCount = pSMB->DataCount;
5884 pSMB->TotalParameterCount = pSMB->ParameterCount;
5885 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5886 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5887 else
5888 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5889 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005890 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005891 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 pSMB->ByteCount = cpu_to_le16(byte_count);
5893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005895 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005896 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897
5898 cifs_buf_release(pSMB);
5899
5900 if (rc == -EAGAIN)
5901 goto SetTimesRetry;
5902
5903 return rc;
5904}
5905
5906/* Can not be used to set time stamps yet (due to old DOS time format) */
5907/* Can be used to set attributes */
5908#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5909 handling it anyway and NT4 was what we thought it would be needed for
5910 Do not delete it until we prove whether needed for Win9x though */
5911int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005912CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 __u16 dos_attrs, const struct nls_table *nls_codepage)
5914{
5915 SETATTR_REQ *pSMB = NULL;
5916 SETATTR_RSP *pSMBr = NULL;
5917 int rc = 0;
5918 int bytes_returned;
5919 int name_len;
5920
Joe Perchesf96637b2013-05-04 22:12:25 -05005921 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
5923SetAttrLgcyRetry:
5924 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5925 (void **) &pSMBr);
5926 if (rc)
5927 return rc;
5928
5929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5930 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005931 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5932 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 name_len++; /* trailing null */
5934 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005935 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 name_len = strnlen(fileName, PATH_MAX);
5937 name_len++; /* trailing null */
5938 strncpy(pSMB->fileName, fileName, name_len);
5939 }
5940 pSMB->attr = cpu_to_le16(dos_attrs);
5941 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005942 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005946 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005947 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948
5949 cifs_buf_release(pSMB);
5950
5951 if (rc == -EAGAIN)
5952 goto SetAttrLgcyRetry;
5953
5954 return rc;
5955}
5956#endif /* temporarily unneeded SetAttr legacy function */
5957
Jeff Layton654cf142009-07-09 20:02:49 -04005958static void
5959cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5960 const struct cifs_unix_set_info_args *args)
5961{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005962 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005963 u64 mode = args->mode;
5964
Eric W. Biederman49418b22013-02-06 00:57:56 -08005965 if (uid_valid(args->uid))
5966 uid = from_kuid(&init_user_ns, args->uid);
5967 if (gid_valid(args->gid))
5968 gid = from_kgid(&init_user_ns, args->gid);
5969
Jeff Layton654cf142009-07-09 20:02:49 -04005970 /*
5971 * Samba server ignores set of file size to zero due to bugs in some
5972 * older clients, but we should be precise - we use SetFileSize to
5973 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005974 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005975 * zero instead of -1 here
5976 */
5977 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5978 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5979 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5980 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5981 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005982 data_offset->Uid = cpu_to_le64(uid);
5983 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005984 /* better to leave device as zero when it is */
5985 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5986 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5987 data_offset->Permissions = cpu_to_le64(mode);
5988
5989 if (S_ISREG(mode))
5990 data_offset->Type = cpu_to_le32(UNIX_FILE);
5991 else if (S_ISDIR(mode))
5992 data_offset->Type = cpu_to_le32(UNIX_DIR);
5993 else if (S_ISLNK(mode))
5994 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5995 else if (S_ISCHR(mode))
5996 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5997 else if (S_ISBLK(mode))
5998 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5999 else if (S_ISFIFO(mode))
6000 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6001 else if (S_ISSOCK(mode))
6002 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6003}
6004
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006006CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006007 const struct cifs_unix_set_info_args *args,
6008 u16 fid, u32 pid_of_opener)
6009{
6010 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006011 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006012 int rc = 0;
6013 u16 params, param_offset, offset, byte_count, count;
6014
Joe Perchesf96637b2013-05-04 22:12:25 -05006015 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006016 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6017
6018 if (rc)
6019 return rc;
6020
6021 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6022 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6023
6024 params = 6;
6025 pSMB->MaxSetupCount = 0;
6026 pSMB->Reserved = 0;
6027 pSMB->Flags = 0;
6028 pSMB->Timeout = 0;
6029 pSMB->Reserved2 = 0;
6030 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6031 offset = param_offset + params;
6032
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006033 data_offset = (char *)pSMB +
6034 offsetof(struct smb_hdr, Protocol) + offset;
6035
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006036 count = sizeof(FILE_UNIX_BASIC_INFO);
6037
6038 pSMB->MaxParameterCount = cpu_to_le16(2);
6039 /* BB find max SMB PDU from sess */
6040 pSMB->MaxDataCount = cpu_to_le16(1000);
6041 pSMB->SetupCount = 1;
6042 pSMB->Reserved3 = 0;
6043 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6044 byte_count = 3 /* pad */ + params + count;
6045 pSMB->DataCount = cpu_to_le16(count);
6046 pSMB->ParameterCount = cpu_to_le16(params);
6047 pSMB->TotalDataCount = pSMB->DataCount;
6048 pSMB->TotalParameterCount = pSMB->ParameterCount;
6049 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6050 pSMB->DataOffset = cpu_to_le16(offset);
6051 pSMB->Fid = fid;
6052 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6053 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006054 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006055 pSMB->ByteCount = cpu_to_le16(byte_count);
6056
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006057 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006058
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006059 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006060 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006061 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6062 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006063
6064 /* Note: On -EAGAIN error only caller can retry on handle based calls
6065 since file handle passed in no longer valid */
6066
6067 return rc;
6068}
6069
6070int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006071CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006072 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006073 const struct cifs_unix_set_info_args *args,
6074 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075{
6076 TRANSACTION2_SPI_REQ *pSMB = NULL;
6077 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6078 int name_len;
6079 int rc = 0;
6080 int bytes_returned = 0;
6081 FILE_UNIX_BASIC_INFO *data_offset;
6082 __u16 params, param_offset, offset, count, byte_count;
6083
Joe Perchesf96637b2013-05-04 22:12:25 -05006084 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085setPermsRetry:
6086 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6087 (void **) &pSMBr);
6088 if (rc)
6089 return rc;
6090
6091 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6092 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006093 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006094 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 name_len++; /* trailing null */
6096 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006097 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006098 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006100 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 }
6102
6103 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006104 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006106 /* BB find max SMB PDU from sess structure BB */
6107 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 pSMB->MaxSetupCount = 0;
6109 pSMB->Reserved = 0;
6110 pSMB->Flags = 0;
6111 pSMB->Timeout = 0;
6112 pSMB->Reserved2 = 0;
6113 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006114 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 offset = param_offset + params;
6116 data_offset =
6117 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6118 offset);
6119 memset(data_offset, 0, count);
6120 pSMB->DataOffset = cpu_to_le16(offset);
6121 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6122 pSMB->SetupCount = 1;
6123 pSMB->Reserved3 = 0;
6124 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6125 byte_count = 3 /* pad */ + params + count;
6126 pSMB->ParameterCount = cpu_to_le16(params);
6127 pSMB->DataCount = cpu_to_le16(count);
6128 pSMB->TotalParameterCount = pSMB->ParameterCount;
6129 pSMB->TotalDataCount = pSMB->DataCount;
6130 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6131 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006132 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006133
Jeff Layton654cf142009-07-09 20:02:49 -04006134 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135
6136 pSMB->ByteCount = cpu_to_le16(byte_count);
6137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006139 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006140 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141
Steve French0d817bc2008-05-22 02:02:03 +00006142 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143 if (rc == -EAGAIN)
6144 goto setPermsRetry;
6145 return rc;
6146}
6147
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006149/*
6150 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6151 * function used by listxattr and getxattr type calls. When ea_name is set,
6152 * it looks for that attribute name and stuffs that value into the EAData
6153 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6154 * buffer. In both cases, the return value is either the length of the
6155 * resulting data or a negative error code. If EAData is a NULL pointer then
6156 * the data isn't copied to it, but the length is returned.
6157 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006159CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006160 const unsigned char *searchName, const unsigned char *ea_name,
6161 char *EAData, size_t buf_size,
6162 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163{
6164 /* BB assumes one setup word */
6165 TRANSACTION2_QPI_REQ *pSMB = NULL;
6166 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6167 int rc = 0;
6168 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006169 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006170 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006171 struct fea *temp_fea;
6172 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006173 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006174 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006175 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176
Joe Perchesf96637b2013-05-04 22:12:25 -05006177 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178QAllEAsRetry:
6179 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6180 (void **) &pSMBr);
6181 if (rc)
6182 return rc;
6183
6184 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006185 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006186 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6187 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006188 list_len++; /* trailing null */
6189 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006191 list_len = strnlen(searchName, PATH_MAX);
6192 list_len++; /* trailing null */
6193 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194 }
6195
Jeff Layton6e462b92010-02-10 16:18:26 -05006196 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197 pSMB->TotalDataCount = 0;
6198 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006199 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006200 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 pSMB->MaxSetupCount = 0;
6202 pSMB->Reserved = 0;
6203 pSMB->Flags = 0;
6204 pSMB->Timeout = 0;
6205 pSMB->Reserved2 = 0;
6206 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006207 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208 pSMB->DataCount = 0;
6209 pSMB->DataOffset = 0;
6210 pSMB->SetupCount = 1;
6211 pSMB->Reserved3 = 0;
6212 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6213 byte_count = params + 1 /* pad */ ;
6214 pSMB->TotalParameterCount = cpu_to_le16(params);
6215 pSMB->ParameterCount = pSMB->TotalParameterCount;
6216 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6217 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006218 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 pSMB->ByteCount = cpu_to_le16(byte_count);
6220
6221 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6222 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6223 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006224 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006225 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006227
6228
6229 /* BB also check enough total bytes returned */
6230 /* BB we need to improve the validity checking
6231 of these trans2 responses */
6232
6233 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006234 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006235 rc = -EIO; /* bad smb */
6236 goto QAllEAsOut;
6237 }
6238
6239 /* check that length of list is not more than bcc */
6240 /* check that each entry does not go beyond length
6241 of list */
6242 /* check that each element of each entry does not
6243 go beyond end of list */
6244 /* validate_trans2_offsets() */
6245 /* BB check if start of smb + data_offset > &bcc+ bcc */
6246
6247 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6248 ea_response_data = (struct fealist *)
6249 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6250
Jeff Layton6e462b92010-02-10 16:18:26 -05006251 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006252 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006253 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006254 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006255 /* didn't find the named attribute */
6256 if (ea_name)
6257 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006258 goto QAllEAsOut;
6259 }
6260
Jeff Layton0cd126b2010-02-10 16:18:26 -05006261 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006262 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006263 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006264 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006265 rc = -EIO;
6266 goto QAllEAsOut;
6267 }
6268
Jeff Laytonf0d38682010-02-10 16:18:26 -05006269 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006270 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006271 temp_fea = ea_response_data->list;
6272 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006273 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006274 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006275 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006276
Jeff Layton6e462b92010-02-10 16:18:26 -05006277 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006278 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006279 /* make sure we can read name_len and value_len */
6280 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006281 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006282 rc = -EIO;
6283 goto QAllEAsOut;
6284 }
6285
6286 name_len = temp_fea->name_len;
6287 value_len = le16_to_cpu(temp_fea->value_len);
6288 list_len -= name_len + 1 + value_len;
6289 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006290 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006291 rc = -EIO;
6292 goto QAllEAsOut;
6293 }
6294
Jeff Layton31c05192010-02-10 16:18:26 -05006295 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006296 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006297 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006298 temp_ptr += name_len + 1;
6299 rc = value_len;
6300 if (buf_size == 0)
6301 goto QAllEAsOut;
6302 if ((size_t)value_len > buf_size) {
6303 rc = -ERANGE;
6304 goto QAllEAsOut;
6305 }
6306 memcpy(EAData, temp_ptr, value_len);
6307 goto QAllEAsOut;
6308 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006309 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006310 /* account for prefix user. and trailing null */
6311 rc += (5 + 1 + name_len);
6312 if (rc < (int) buf_size) {
6313 memcpy(EAData, "user.", 5);
6314 EAData += 5;
6315 memcpy(EAData, temp_ptr, name_len);
6316 EAData += name_len;
6317 /* null terminate name */
6318 *EAData = 0;
6319 ++EAData;
6320 } else if (buf_size == 0) {
6321 /* skip copy - calc size only */
6322 } else {
6323 /* stop before overrun buffer */
6324 rc = -ERANGE;
6325 break;
6326 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006327 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006328 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006329 temp_fea = (struct fea *)temp_ptr;
6330 }
6331
Jeff Layton31c05192010-02-10 16:18:26 -05006332 /* didn't find the named attribute */
6333 if (ea_name)
6334 rc = -ENODATA;
6335
Jeff Laytonf0d38682010-02-10 16:18:26 -05006336QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006337 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 if (rc == -EAGAIN)
6339 goto QAllEAsRetry;
6340
6341 return (ssize_t)rc;
6342}
6343
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006345CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6346 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006347 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6348 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349{
6350 struct smb_com_transaction2_spi_req *pSMB = NULL;
6351 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6352 struct fealist *parm_data;
6353 int name_len;
6354 int rc = 0;
6355 int bytes_returned = 0;
6356 __u16 params, param_offset, byte_count, offset, count;
6357
Joe Perchesf96637b2013-05-04 22:12:25 -05006358 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359SetEARetry:
6360 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6361 (void **) &pSMBr);
6362 if (rc)
6363 return rc;
6364
6365 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6366 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006367 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6368 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 name_len++; /* trailing null */
6370 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006371 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 name_len = strnlen(fileName, PATH_MAX);
6373 name_len++; /* trailing null */
6374 strncpy(pSMB->FileName, fileName, name_len);
6375 }
6376
6377 params = 6 + name_len;
6378
6379 /* done calculating parms using name_len of file name,
6380 now use name_len to calculate length of ea name
6381 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006382 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 name_len = 0;
6384 else
Steve French50c2f752007-07-13 00:33:32 +00006385 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006387 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006389 /* BB find max SMB PDU from sess */
6390 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391 pSMB->MaxSetupCount = 0;
6392 pSMB->Reserved = 0;
6393 pSMB->Flags = 0;
6394 pSMB->Timeout = 0;
6395 pSMB->Reserved2 = 0;
6396 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006397 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398 offset = param_offset + params;
6399 pSMB->InformationLevel =
6400 cpu_to_le16(SMB_SET_FILE_EA);
6401
6402 parm_data =
6403 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6404 offset);
6405 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6406 pSMB->DataOffset = cpu_to_le16(offset);
6407 pSMB->SetupCount = 1;
6408 pSMB->Reserved3 = 0;
6409 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6410 byte_count = 3 /* pad */ + params + count;
6411 pSMB->DataCount = cpu_to_le16(count);
6412 parm_data->list_len = cpu_to_le32(count);
6413 parm_data->list[0].EA_flags = 0;
6414 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006415 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006417 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006418 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419 parm_data->list[0].name[name_len] = 0;
6420 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6421 /* caller ensures that ea_value_len is less than 64K but
6422 we need to ensure that it fits within the smb */
6423
Steve French50c2f752007-07-13 00:33:32 +00006424 /*BB add length check to see if it would fit in
6425 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006426 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6427 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006428 memcpy(parm_data->list[0].name+name_len+1,
6429 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006430
6431 pSMB->TotalDataCount = pSMB->DataCount;
6432 pSMB->ParameterCount = cpu_to_le16(params);
6433 pSMB->TotalParameterCount = pSMB->ParameterCount;
6434 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006435 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436 pSMB->ByteCount = cpu_to_le16(byte_count);
6437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006439 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006440 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006441
6442 cifs_buf_release(pSMB);
6443
6444 if (rc == -EAGAIN)
6445 goto SetEARetry;
6446
6447 return rc;
6448}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449#endif
Steve French0eff0e22011-02-24 05:39:23 +00006450
6451#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6452/*
6453 * Years ago the kernel added a "dnotify" function for Samba server,
6454 * to allow network clients (such as Windows) to display updated
6455 * lists of files in directory listings automatically when
6456 * files are added by one user when another user has the
6457 * same directory open on their desktop. The Linux cifs kernel
6458 * client hooked into the kernel side of this interface for
6459 * the same reason, but ironically when the VFS moved from
6460 * "dnotify" to "inotify" it became harder to plug in Linux
6461 * network file system clients (the most obvious use case
6462 * for notify interfaces is when multiple users can update
6463 * the contents of the same directory - exactly what network
6464 * file systems can do) although the server (Samba) could
6465 * still use it. For the short term we leave the worker
6466 * function ifdeffed out (below) until inotify is fixed
6467 * in the VFS to make it easier to plug in network file
6468 * system clients. If inotify turns out to be permanently
6469 * incompatible for network fs clients, we could instead simply
6470 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6471 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006472int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006473 const int notify_subdirs, const __u16 netfid,
6474 __u32 filter, struct file *pfile, int multishot,
6475 const struct nls_table *nls_codepage)
6476{
6477 int rc = 0;
6478 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6479 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6480 struct dir_notify_req *dnotify_req;
6481 int bytes_returned;
6482
Joe Perchesf96637b2013-05-04 22:12:25 -05006483 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006484 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6485 (void **) &pSMBr);
6486 if (rc)
6487 return rc;
6488
6489 pSMB->TotalParameterCount = 0 ;
6490 pSMB->TotalDataCount = 0;
6491 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006492 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006493 pSMB->MaxSetupCount = 4;
6494 pSMB->Reserved = 0;
6495 pSMB->ParameterOffset = 0;
6496 pSMB->DataCount = 0;
6497 pSMB->DataOffset = 0;
6498 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6499 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6500 pSMB->ParameterCount = pSMB->TotalParameterCount;
6501 if (notify_subdirs)
6502 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6503 pSMB->Reserved2 = 0;
6504 pSMB->CompletionFilter = cpu_to_le32(filter);
6505 pSMB->Fid = netfid; /* file handle always le */
6506 pSMB->ByteCount = 0;
6507
6508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6509 (struct smb_hdr *)pSMBr, &bytes_returned,
6510 CIFS_ASYNC_OP);
6511 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006512 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006513 } else {
6514 /* Add file to outstanding requests */
6515 /* BB change to kmem cache alloc */
6516 dnotify_req = kmalloc(
6517 sizeof(struct dir_notify_req),
6518 GFP_KERNEL);
6519 if (dnotify_req) {
6520 dnotify_req->Pid = pSMB->hdr.Pid;
6521 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6522 dnotify_req->Mid = pSMB->hdr.Mid;
6523 dnotify_req->Tid = pSMB->hdr.Tid;
6524 dnotify_req->Uid = pSMB->hdr.Uid;
6525 dnotify_req->netfid = netfid;
6526 dnotify_req->pfile = pfile;
6527 dnotify_req->filter = filter;
6528 dnotify_req->multishot = multishot;
6529 spin_lock(&GlobalMid_Lock);
6530 list_add_tail(&dnotify_req->lhead,
6531 &GlobalDnotifyReqList);
6532 spin_unlock(&GlobalMid_Lock);
6533 } else
6534 rc = -ENOMEM;
6535 }
6536 cifs_buf_release(pSMB);
6537 return rc;
6538}
6539#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */