blob: 586fdac05ec2fa2b4aa048d445de29444df7ca99 [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 Frencha4544342005-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 Frencha4544342005-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);
Sachin Prabhud8fd99d2017-03-03 15:41:38 -08001426 mid->resp_buf = server->smallbuf;
1427 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001428 return length;
1429}
1430
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001431int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1433{
1434 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001435 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001436 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001437 char *buf = server->smallbuf;
1438 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001439
Joe Perchesf96637b2013-05-04 22:12:25 -05001440 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1441 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001442
1443 /*
1444 * read the rest of READ_RSP header (sans Data array), or whatever we
1445 * can if there's not enough data. At this point, we've read down to
1446 * the Mid.
1447 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001448 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001449 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450
Al Viroa6137302016-01-09 19:37:16 -05001451 length = cifs_read_from_socket(server,
1452 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453 if (length < 0)
1454 return length;
1455 server->total_read += length;
1456
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001457 if (server->ops->is_status_pending &&
1458 server->ops->is_status_pending(buf, server, 0)) {
1459 discard_remaining_data(server);
1460 return -1;
1461 }
1462
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001464 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001466 cifs_dbg(FYI, "%s: server returned error %d\n",
1467 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001468 return cifs_readv_discard(server, mid);
1469 }
1470
1471 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001472 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001473 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1474 __func__, server->total_read,
1475 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476 rdata->result = -EIO;
1477 return cifs_readv_discard(server, mid);
1478 }
1479
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001480 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 if (data_offset < server->total_read) {
1482 /*
1483 * win2k8 sometimes sends an offset of 0 when the read
1484 * is beyond the EOF. Treat it as if the data starts just after
1485 * the header.
1486 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001487 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1488 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 data_offset = server->total_read;
1490 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1491 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001492 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1493 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001494 rdata->result = -EIO;
1495 return cifs_readv_discard(server, mid);
1496 }
1497
Joe Perchesf96637b2013-05-04 22:12:25 -05001498 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1499 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001500
1501 len = data_offset - server->total_read;
1502 if (len > 0) {
1503 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001504 length = cifs_read_from_socket(server,
1505 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506 if (length < 0)
1507 return length;
1508 server->total_read += length;
1509 }
1510
1511 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001512 rdata->iov.iov_base = buf;
1513 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001514 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1515 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516
1517 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001518 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001519 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520 /* data_len is corrupt -- discard frame */
1521 rdata->result = -EIO;
1522 return cifs_readv_discard(server, mid);
1523 }
1524
Jeff Layton8321fec2012-09-19 06:22:32 -07001525 length = rdata->read_into_pages(server, rdata, data_len);
1526 if (length < 0)
1527 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528
Jeff Layton8321fec2012-09-19 06:22:32 -07001529 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001530
Joe Perchesf96637b2013-05-04 22:12:25 -05001531 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1532 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001533
1534 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001535 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536 return cifs_readv_discard(server, mid);
1537
1538 dequeue_mid(mid, false);
Sachin Prabhud8fd99d2017-03-03 15:41:38 -08001539 mid->resp_buf = server->smallbuf;
1540 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541 return length;
1542}
1543
1544static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545cifs_readv_callback(struct mid_q_entry *mid)
1546{
1547 struct cifs_readdata *rdata = mid->callback_data;
1548 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1549 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001550 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1551 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001552 .rq_pages = rdata->pages,
1553 .rq_npages = rdata->nr_pages,
1554 .rq_pagesz = rdata->pagesz,
1555 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556
Joe Perchesf96637b2013-05-04 22:12:25 -05001557 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1558 __func__, mid->mid, mid->mid_state, rdata->result,
1559 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001561 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001562 case MID_RESPONSE_RECEIVED:
1563 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001564 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001565 int rc = 0;
1566
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001567 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001568 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001569 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001570 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1571 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572 }
1573 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001574 task_io_account_read(rdata->got_bytes);
1575 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001576 break;
1577 case MID_REQUEST_SUBMITTED:
1578 case MID_RETRY_NEEDED:
1579 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001580 if (server->sign && rdata->got_bytes)
1581 /* reset bytes number since we can not check a sign */
1582 rdata->got_bytes = 0;
1583 /* FIXME: should this be counted toward the initiating task? */
1584 task_io_account_read(rdata->got_bytes);
1585 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001586 break;
1587 default:
1588 rdata->result = -EIO;
1589 }
1590
Jeff Laytonda472fc2012-03-23 14:40:53 -04001591 queue_work(cifsiod_wq, &rdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001592 mutex_lock(&server->srv_mutex);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001593 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07001594 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001595 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001596}
1597
1598/* cifs_async_readv - send an async write, and set up mid to handle result */
1599int
1600cifs_async_readv(struct cifs_readdata *rdata)
1601{
1602 int rc;
1603 READ_REQ *smb = NULL;
1604 int wct;
1605 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001606 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001607 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608
Joe Perchesf96637b2013-05-04 22:12:25 -05001609 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1610 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001611
1612 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1613 wct = 12;
1614 else {
1615 wct = 10; /* old style read */
1616 if ((rdata->offset >> 32) > 0) {
1617 /* can not handle this big offset for old */
1618 return -EIO;
1619 }
1620 }
1621
1622 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1623 if (rc)
1624 return rc;
1625
1626 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1627 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1628
1629 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001630 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001631 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1632 if (wct == 12)
1633 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1634 smb->Remaining = 0;
1635 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1636 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1637 if (wct == 12)
1638 smb->ByteCount = 0;
1639 else {
1640 /* old style read */
1641 struct smb_com_readx_req *smbr =
1642 (struct smb_com_readx_req *)smb;
1643 smbr->ByteCount = 0;
1644 }
1645
1646 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001647 rdata->iov.iov_base = smb;
1648 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001649
Jeff Layton6993f742012-05-16 07:13:17 -04001650 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001651 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1652 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001653
1654 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001655 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001656 else
1657 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658
1659 cifs_small_buf_release(smb);
1660 return rc;
1661}
1662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001664CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1665 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666{
1667 int rc = -EACCES;
1668 READ_REQ *pSMB = NULL;
1669 READ_RSP *pSMBr = NULL;
1670 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001671 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001672 int resp_buf_type = 0;
1673 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001674 __u32 pid = io_parms->pid;
1675 __u16 netfid = io_parms->netfid;
1676 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001677 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001678 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
Joe Perchesf96637b2013-05-04 22:12:25 -05001680 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001681 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001682 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001683 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001684 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001685 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001686 /* can not handle this big offset for old */
1687 return -EIO;
1688 }
1689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001692 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (rc)
1694 return rc;
1695
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001696 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1697 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 /* tcon and ses pointer are checked in smb_init */
1700 if (tcon->ses->server == NULL)
1701 return -ECONNABORTED;
1702
Steve Frenchec637e32005-12-12 20:53:18 -08001703 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001705 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001706 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001707 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 pSMB->Remaining = 0;
1710 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1711 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001712 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001713 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1714 else {
1715 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001716 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001717 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001718 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001719 }
Steve Frenchec637e32005-12-12 20:53:18 -08001720
1721 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001722 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001723 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001724 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001725 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001726 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001728 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 } else {
1730 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1731 data_length = data_length << 16;
1732 data_length += le16_to_cpu(pSMBr->DataLength);
1733 *nbytes = data_length;
1734
1735 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001736 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001738 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001739 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 rc = -EIO;
1741 *nbytes = 0;
1742 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001743 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001744 le16_to_cpu(pSMBr->DataOffset);
1745/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001746 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001747 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001748 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001749 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001750 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Steve French4b8f9302006-02-26 16:41:18 +00001754/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001755 if (*buf) {
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01001756 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001757 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001758 /* return buffer to caller to free */
1759 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001760 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001761 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001762 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001763 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001764 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001765
1766 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 since file handle passed in no longer valid */
1768 return rc;
1769}
1770
Steve Frenchec637e32005-12-12 20:53:18 -08001771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001773CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001774 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775{
1776 int rc = -EACCES;
1777 WRITE_REQ *pSMB = NULL;
1778 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001779 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 __u32 bytes_sent;
1781 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001782 __u32 pid = io_parms->pid;
1783 __u16 netfid = io_parms->netfid;
1784 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001785 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001786 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Steve Frencha24e2d72010-04-03 17:20:21 +00001788 *nbytes = 0;
1789
Joe Perchesf96637b2013-05-04 22:12:25 -05001790 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001791 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001792 return -ECONNABORTED;
1793
Steve French790fe572007-07-07 19:25:05 +00001794 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001795 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001796 else {
Steve French1c955182005-08-30 20:58:07 -07001797 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001798 if ((offset >> 32) > 0) {
1799 /* can not handle big offset for old srv */
1800 return -EIO;
1801 }
1802 }
Steve French1c955182005-08-30 20:58:07 -07001803
1804 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 (void **) &pSMBr);
1806 if (rc)
1807 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001808
1809 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1810 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 /* tcon and ses pointer are checked in smb_init */
1813 if (tcon->ses->server == NULL)
1814 return -ECONNABORTED;
1815
1816 pSMB->AndXCommand = 0xFF; /* none */
1817 pSMB->Fid = netfid;
1818 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001819 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001820 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 pSMB->Reserved = 0xFFFFFFFF;
1823 pSMB->WriteMode = 0;
1824 pSMB->Remaining = 0;
1825
Steve French50c2f752007-07-13 00:33:32 +00001826 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 can send more if LARGE_WRITE_X capability returned by the server and if
1828 our buffer is big enough or if we convert to iovecs on socket writes
1829 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001830 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1832 } else {
1833 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1834 & ~0xFF;
1835 }
1836
1837 if (bytes_sent > count)
1838 bytes_sent = count;
1839 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001840 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001841 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001842 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001843 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* No buffer */
1845 cifs_buf_release(pSMB);
1846 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001847 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001848 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001849 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001850 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001851 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1854 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001855 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001856
Steve French790fe572007-07-07 19:25:05 +00001857 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001858 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001859 else { /* old style write has byte count 4 bytes earlier
1860 so 4 bytes pad */
1861 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001862 (struct smb_com_writex_req *)pSMB;
1863 pSMBW->ByteCount = cpu_to_le16(byte_count);
1864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001868 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001870 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 } else {
1872 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1873 *nbytes = (*nbytes) << 16;
1874 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301875
1876 /*
1877 * Mask off high 16 bits when bytes written as returned by the
1878 * server is greater than bytes requested by the client. Some
1879 * OS/2 servers are known to set incorrect CountHigh values.
1880 */
1881 if (*nbytes > count)
1882 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 }
1884
1885 cifs_buf_release(pSMB);
1886
Steve French50c2f752007-07-13 00:33:32 +00001887 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 since file handle passed in no longer valid */
1889
1890 return rc;
1891}
1892
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001893void
1894cifs_writedata_release(struct kref *refcount)
1895{
1896 struct cifs_writedata *wdata = container_of(refcount,
1897 struct cifs_writedata, refcount);
1898
1899 if (wdata->cfile)
1900 cifsFileInfo_put(wdata->cfile);
1901
1902 kfree(wdata);
1903}
1904
1905/*
1906 * Write failed with a retryable error. Resend the write request. It's also
1907 * possible that the page was redirtied so re-clean the page.
1908 */
1909static void
1910cifs_writev_requeue(struct cifs_writedata *wdata)
1911{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001912 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001913 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001914 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001915 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001916
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001917 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1918 i = 0;
1919 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001920 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001921 struct cifs_writedata *wdata2;
1922 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001923
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001924 wsize = server->ops->wp_retry_size(inode);
1925 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001926 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001927 if (!nr_pages) {
1928 rc = -ENOTSUPP;
1929 break;
1930 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001931 cur_len = nr_pages * PAGE_SIZE;
1932 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001933 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001934 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001935 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001936 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001937 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001938
1939 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1940 if (!wdata2) {
1941 rc = -ENOMEM;
1942 break;
1943 }
1944
1945 for (j = 0; j < nr_pages; j++) {
1946 wdata2->pages[j] = wdata->pages[i + j];
1947 lock_page(wdata2->pages[j]);
1948 clear_page_dirty_for_io(wdata2->pages[j]);
1949 }
1950
1951 wdata2->sync_mode = wdata->sync_mode;
1952 wdata2->nr_pages = nr_pages;
1953 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001954 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001955 wdata2->tailsz = tailsz;
1956 wdata2->bytes = cur_len;
1957
1958 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1959 if (!wdata2->cfile) {
1960 cifs_dbg(VFS, "No writable handles for inode\n");
1961 rc = -EBADF;
1962 break;
1963 }
1964 wdata2->pid = wdata2->cfile->pid;
1965 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1966
1967 for (j = 0; j < nr_pages; j++) {
1968 unlock_page(wdata2->pages[j]);
1969 if (rc != 0 && rc != -EAGAIN) {
1970 SetPageError(wdata2->pages[j]);
1971 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001972 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001973 }
1974 }
1975
1976 if (rc) {
1977 kref_put(&wdata2->refcount, cifs_writedata_release);
1978 if (rc == -EAGAIN)
1979 continue;
1980 break;
1981 }
1982
1983 rest_len -= cur_len;
1984 i += nr_pages;
1985 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001986
1987 mapping_set_error(inode->i_mapping, rc);
1988 kref_put(&wdata->refcount, cifs_writedata_release);
1989}
1990
Jeff Laytonc2e87642012-03-23 14:40:55 -04001991void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001992cifs_writev_complete(struct work_struct *work)
1993{
1994 struct cifs_writedata *wdata = container_of(work,
1995 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00001996 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001997 int i = 0;
1998
1999 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002000 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002001 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002002 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002003 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2004 wdata->bytes);
2005 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2006 return cifs_writev_requeue(wdata);
2007
2008 for (i = 0; i < wdata->nr_pages; i++) {
2009 struct page *page = wdata->pages[i];
2010 if (wdata->result == -EAGAIN)
2011 __set_page_dirty_nobuffers(page);
2012 else if (wdata->result < 0)
2013 SetPageError(page);
2014 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002015 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002016 }
2017 if (wdata->result != -EAGAIN)
2018 mapping_set_error(inode->i_mapping, wdata->result);
2019 kref_put(&wdata->refcount, cifs_writedata_release);
2020}
2021
2022struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002023cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002024{
2025 struct cifs_writedata *wdata;
2026
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002027 /* writedata + number of page pointers */
2028 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002029 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002030 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002031 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002032 INIT_LIST_HEAD(&wdata->list);
2033 init_completion(&wdata->done);
2034 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002035 }
2036 return wdata;
2037}
2038
2039/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002040 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002041 * workqueue completion task.
2042 */
2043static void
2044cifs_writev_callback(struct mid_q_entry *mid)
2045{
2046 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002047 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002048 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002049 unsigned int written;
2050 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2051
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002052 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002053 case MID_RESPONSE_RECEIVED:
2054 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2055 if (wdata->result != 0)
2056 break;
2057
2058 written = le16_to_cpu(smb->CountHigh);
2059 written <<= 16;
2060 written += le16_to_cpu(smb->Count);
2061 /*
2062 * Mask off high 16 bits when bytes written as returned
2063 * by the server is greater than bytes requested by the
2064 * client. OS/2 servers are known to set incorrect
2065 * CountHigh values.
2066 */
2067 if (written > wdata->bytes)
2068 written &= 0xFFFF;
2069
2070 if (written < wdata->bytes)
2071 wdata->result = -ENOSPC;
2072 else
2073 wdata->bytes = written;
2074 break;
2075 case MID_REQUEST_SUBMITTED:
2076 case MID_RETRY_NEEDED:
2077 wdata->result = -EAGAIN;
2078 break;
2079 default:
2080 wdata->result = -EIO;
2081 break;
2082 }
2083
Jeff Laytonda472fc2012-03-23 14:40:53 -04002084 queue_work(cifsiod_wq, &wdata->work);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002085 mutex_lock(&server->srv_mutex);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002086 DeleteMidQEntry(mid);
Christopher Oo5fb4e282015-06-25 16:10:48 -07002087 mutex_unlock(&server->srv_mutex);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002088 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002089}
2090
2091/* cifs_async_writev - send an async write, and set up mid to handle result */
2092int
Steve French4a5c80d2014-02-07 20:45:12 -06002093cifs_async_writev(struct cifs_writedata *wdata,
2094 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002096 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002097 WRITE_REQ *smb = NULL;
2098 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002099 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002100 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002101 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102
2103 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2104 wct = 14;
2105 } else {
2106 wct = 12;
2107 if (wdata->offset >> 32 > 0) {
2108 /* can not handle big offset for old srv */
2109 return -EIO;
2110 }
2111 }
2112
2113 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2114 if (rc)
2115 goto async_writev_out;
2116
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002117 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2118 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002119
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002120 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002121 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2123 if (wct == 14)
2124 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2125 smb->Reserved = 0xFFFFFFFF;
2126 smb->WriteMode = 0;
2127 smb->Remaining = 0;
2128
2129 smb->DataOffset =
2130 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2131
2132 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002133 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2134 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002135
Jeff Laytoneddb0792012-09-18 16:20:35 -07002136 rqst.rq_iov = &iov;
2137 rqst.rq_nvec = 1;
2138 rqst.rq_pages = wdata->pages;
2139 rqst.rq_npages = wdata->nr_pages;
2140 rqst.rq_pagesz = wdata->pagesz;
2141 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002142
Joe Perchesf96637b2013-05-04 22:12:25 -05002143 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2144 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002145
2146 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2147 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2148
2149 if (wct == 14) {
2150 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2151 put_bcc(wdata->bytes + 1, &smb->hdr);
2152 } else {
2153 /* wct == 12 */
2154 struct smb_com_writex_req *smbw =
2155 (struct smb_com_writex_req *)smb;
2156 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2157 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002158 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002159 }
2160
2161 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002162 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2163 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002164
2165 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002166 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002167 else
Steve French4a5c80d2014-02-07 20:45:12 -06002168 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002170async_writev_out:
2171 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002172 return rc;
2173}
2174
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002175int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002176CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002177 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178{
2179 int rc = -EACCES;
2180 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002181 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002182 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002183 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002184 __u32 pid = io_parms->pid;
2185 __u16 netfid = io_parms->netfid;
2186 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002187 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002188 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002190 *nbytes = 0;
2191
Joe Perchesf96637b2013-05-04 22:12:25 -05002192 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002193
Steve French4c3130e2008-12-09 00:28:16 +00002194 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002195 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002196 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002197 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002198 if ((offset >> 32) > 0) {
2199 /* can not handle big offset for old srv */
2200 return -EIO;
2201 }
2202 }
Steve French8cc64c62005-10-03 13:49:43 -07002203 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 if (rc)
2205 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002206
2207 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2208 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2209
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 /* tcon and ses pointer are checked in smb_init */
2211 if (tcon->ses->server == NULL)
2212 return -ECONNABORTED;
2213
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002214 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 pSMB->Fid = netfid;
2216 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002217 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002218 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 pSMB->Reserved = 0xFFFFFFFF;
2220 pSMB->WriteMode = 0;
2221 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002224 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Steve French3e844692005-10-03 13:37:24 -07002226 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2227 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002228 /* header + 1 byte pad */
2229 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002230 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002231 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002232 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002233 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002234 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002235 pSMB->ByteCount = cpu_to_le16(count + 1);
2236 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002237 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002238 (struct smb_com_writex_req *)pSMB;
2239 pSMBW->ByteCount = cpu_to_le16(count + 5);
2240 }
Steve French3e844692005-10-03 13:37:24 -07002241 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002242 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002243 iov[0].iov_len = smb_hdr_len + 4;
2244 else /* wct == 12 pad bigger by four bytes */
2245 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002246
Steve French3e844692005-10-03 13:37:24 -07002247
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002248 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002249 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002251 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002252 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002253 /* presumably this can not happen, but best to be safe */
2254 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002255 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002256 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002257 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2258 *nbytes = (*nbytes) << 16;
2259 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302260
2261 /*
2262 * Mask off high 16 bits when bytes written as returned by the
2263 * server is greater than bytes requested by the client. OS/2
2264 * servers are known to set incorrect CountHigh values.
2265 */
2266 if (*nbytes > count)
2267 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
Steve French4b8f9302006-02-26 16:41:18 +00002270/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002271 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
Steve French50c2f752007-07-13 00:33:32 +00002273 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 since file handle passed in no longer valid */
2275
2276 return rc;
2277}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002278
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002279int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2280 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002281 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2282{
2283 int rc = 0;
2284 LOCK_REQ *pSMB = NULL;
2285 struct kvec iov[2];
2286 int resp_buf_type;
2287 __u16 count;
2288
Joe Perchesf96637b2013-05-04 22:12:25 -05002289 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2290 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002291
2292 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2293 if (rc)
2294 return rc;
2295
2296 pSMB->Timeout = 0;
2297 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2298 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2299 pSMB->LockType = lock_type;
2300 pSMB->AndXCommand = 0xFF; /* none */
2301 pSMB->Fid = netfid; /* netfid stays le */
2302
2303 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2304 inc_rfc1001_len(pSMB, count);
2305 pSMB->ByteCount = cpu_to_le16(count);
2306
2307 iov[0].iov_base = (char *)pSMB;
2308 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2309 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2310 iov[1].iov_base = (char *)buf;
2311 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2312
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002313 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002314 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2315 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002316 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002317
2318 return rc;
2319}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002320
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002322CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002323 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002325 const __u32 numLock, const __u8 lockType,
2326 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327{
2328 int rc = 0;
2329 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002330/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002332 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 __u16 count;
2334
Joe Perchesf96637b2013-05-04 22:12:25 -05002335 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2336 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002337 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2338
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 if (rc)
2340 return rc;
2341
Steve French790fe572007-07-07 19:25:05 +00002342 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002343 /* no response expected */
2344 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002346 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002347 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2349 } else {
2350 pSMB->Timeout = 0;
2351 }
2352
2353 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2354 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2355 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002356 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 pSMB->AndXCommand = 0xFF; /* none */
2358 pSMB->Fid = smb_file_id; /* netfid stays le */
2359
Steve French790fe572007-07-07 19:25:05 +00002360 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002361 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 /* BB where to store pid high? */
2363 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2364 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2365 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2366 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2367 count = sizeof(LOCKING_ANDX_RANGE);
2368 } else {
2369 /* oplock break */
2370 count = 0;
2371 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002372 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 pSMB->ByteCount = cpu_to_le16(count);
2374
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002375 if (waitFlag) {
2376 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002377 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002378 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002379 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002380 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002381 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002382 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002383 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002384 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002385 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Steve French50c2f752007-07-13 00:33:32 +00002387 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 since file handle passed in no longer valid */
2389 return rc;
2390}
2391
2392int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002393CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002394 const __u16 smb_file_id, const __u32 netpid,
2395 const loff_t start_offset, const __u64 len,
2396 struct file_lock *pLockData, const __u16 lock_type,
2397 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002398{
2399 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2400 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002401 struct cifs_posix_lock *parm_data;
2402 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002403 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002404 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002405 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002406 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002407 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002408
Joe Perchesf96637b2013-05-04 22:12:25 -05002409 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002410
Steve French08547b02006-02-28 22:39:25 +00002411 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2412
2413 if (rc)
2414 return rc;
2415
2416 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2417
Steve French50c2f752007-07-13 00:33:32 +00002418 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002419 pSMB->MaxSetupCount = 0;
2420 pSMB->Reserved = 0;
2421 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002422 pSMB->Reserved2 = 0;
2423 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2424 offset = param_offset + params;
2425
Steve French08547b02006-02-28 22:39:25 +00002426 count = sizeof(struct cifs_posix_lock);
2427 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002428 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002429 pSMB->SetupCount = 1;
2430 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002431 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2433 else
2434 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2435 byte_count = 3 /* pad */ + params + count;
2436 pSMB->DataCount = cpu_to_le16(count);
2437 pSMB->ParameterCount = cpu_to_le16(params);
2438 pSMB->TotalDataCount = pSMB->DataCount;
2439 pSMB->TotalParameterCount = pSMB->ParameterCount;
2440 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002441 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002442 (((char *) &pSMB->hdr.Protocol) + offset);
2443
2444 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002445 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002446 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002447 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002448 pSMB->Timeout = cpu_to_le32(-1);
2449 } else
2450 pSMB->Timeout = 0;
2451
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002452 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002453 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002454 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002455
2456 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002457 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002458 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2459 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002460 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002461 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002462 if (waitFlag) {
2463 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2464 (struct smb_hdr *) pSMBr, &bytes_returned);
2465 } else {
Steve French133672e2007-11-13 22:41:37 +00002466 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002467 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002468 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2469 &resp_buf_type, timeout);
2470 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2471 not try to free it twice below on exit */
2472 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002473 }
2474
Steve French08547b02006-02-28 22:39:25 +00002475 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002476 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002477 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002478 /* lock structure can be returned on get */
2479 __u16 data_offset;
2480 __u16 data_count;
2481 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002482
Jeff Layton820a8032011-05-04 08:05:26 -04002483 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002484 rc = -EIO; /* bad smb */
2485 goto plk_err_exit;
2486 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002487 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2488 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002489 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002490 rc = -EIO;
2491 goto plk_err_exit;
2492 }
2493 parm_data = (struct cifs_posix_lock *)
2494 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002495 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002496 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002497 else {
2498 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002499 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002500 pLockData->fl_type = F_RDLCK;
2501 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002502 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002503 pLockData->fl_type = F_WRLCK;
2504
Steve French5443d132011-03-13 05:08:25 +00002505 pLockData->fl_start = le64_to_cpu(parm_data->start);
2506 pLockData->fl_end = pLockData->fl_start +
2507 le64_to_cpu(parm_data->length) - 1;
2508 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002509 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002510 }
Steve French50c2f752007-07-13 00:33:32 +00002511
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002512plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002513 if (pSMB)
2514 cifs_small_buf_release(pSMB);
2515
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002516 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French133672e2007-11-13 22:41:37 +00002517
Steve French08547b02006-02-28 22:39:25 +00002518 /* Note: On -EAGAIN error only caller can retry on handle based calls
2519 since file handle passed in no longer valid */
2520
2521 return rc;
2522}
2523
2524
2525int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002526CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527{
2528 int rc = 0;
2529 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002530 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
2532/* do not retry on dead session on close */
2533 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002534 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 return 0;
2536 if (rc)
2537 return rc;
2538
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002540 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002542 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002543 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002545 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002547 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 }
2549 }
2550
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002552 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 rc = 0;
2554
2555 return rc;
2556}
2557
2558int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002559CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002560{
2561 int rc = 0;
2562 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002563 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002564
2565 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2566 if (rc)
2567 return rc;
2568
2569 pSMB->FileID = (__u16) smb_file_id;
2570 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002571 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002572 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002573 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002574 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002575
2576 return rc;
2577}
2578
2579int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002580CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002581 const char *from_name, const char *to_name,
2582 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583{
2584 int rc = 0;
2585 RENAME_REQ *pSMB = NULL;
2586 RENAME_RSP *pSMBr = NULL;
2587 int bytes_returned;
2588 int name_len, name_len2;
2589 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002590 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
Joe Perchesf96637b2013-05-04 22:12:25 -05002592 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593renameRetry:
2594 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2595 (void **) &pSMBr);
2596 if (rc)
2597 return rc;
2598
2599 pSMB->BufferFormat = 0x04;
2600 pSMB->SearchAttributes =
2601 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2602 ATTR_DIRECTORY);
2603
2604 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002605 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2606 from_name, PATH_MAX,
2607 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 name_len++; /* trailing null */
2609 name_len *= 2;
2610 pSMB->OldFileName[name_len] = 0x04; /* pad */
2611 /* protocol requires ASCII signature byte on Unicode string */
2612 pSMB->OldFileName[name_len + 1] = 0x00;
2613 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002614 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002615 to_name, PATH_MAX, cifs_sb->local_nls,
2616 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2618 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002619 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002620 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002622 strncpy(pSMB->OldFileName, from_name, name_len);
2623 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 name_len2++; /* trailing null */
2625 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002626 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 name_len2++; /* trailing null */
2628 name_len2++; /* signature byte */
2629 }
2630
2631 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002632 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 pSMB->ByteCount = cpu_to_le16(count);
2634
2635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002637 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002638 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002639 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 cifs_buf_release(pSMB);
2642
2643 if (rc == -EAGAIN)
2644 goto renameRetry;
2645
2646 return rc;
2647}
2648
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002649int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002650 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002651 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652{
2653 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2654 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002655 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 char *data_offset;
2657 char dummy_string[30];
2658 int rc = 0;
2659 int bytes_returned = 0;
2660 int len_of_str;
2661 __u16 params, param_offset, offset, count, byte_count;
2662
Joe Perchesf96637b2013-05-04 22:12:25 -05002663 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2665 (void **) &pSMBr);
2666 if (rc)
2667 return rc;
2668
2669 params = 6;
2670 pSMB->MaxSetupCount = 0;
2671 pSMB->Reserved = 0;
2672 pSMB->Flags = 0;
2673 pSMB->Timeout = 0;
2674 pSMB->Reserved2 = 0;
2675 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2676 offset = param_offset + params;
2677
2678 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2679 rename_info = (struct set_file_rename *) data_offset;
2680 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002681 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 pSMB->SetupCount = 1;
2683 pSMB->Reserved3 = 0;
2684 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2685 byte_count = 3 /* pad */ + params;
2686 pSMB->ParameterCount = cpu_to_le16(params);
2687 pSMB->TotalParameterCount = pSMB->ParameterCount;
2688 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2689 pSMB->DataOffset = cpu_to_le16(offset);
2690 /* construct random name ".cifs_tmp<inodenum><mid>" */
2691 rename_info->overwrite = cpu_to_le32(1);
2692 rename_info->root_fid = 0;
2693 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002694 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002695 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002696 len_of_str =
2697 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002698 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002700 len_of_str =
2701 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002702 target_name, PATH_MAX, nls_codepage,
2703 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 }
2705 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002706 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 byte_count += count;
2708 pSMB->DataCount = cpu_to_le16(count);
2709 pSMB->TotalDataCount = pSMB->DataCount;
2710 pSMB->Fid = netfid;
2711 pSMB->InformationLevel =
2712 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2713 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002714 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 pSMB->ByteCount = cpu_to_le16(byte_count);
2716 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002717 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002718 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002719 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002720 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2721 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002722
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 cifs_buf_release(pSMB);
2724
2725 /* Note: On -EAGAIN error only caller can retry on handle based calls
2726 since file handle passed in no longer valid */
2727
2728 return rc;
2729}
2730
2731int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002732CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2733 const char *fromName, const __u16 target_tid, const char *toName,
2734 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735{
2736 int rc = 0;
2737 COPY_REQ *pSMB = NULL;
2738 COPY_RSP *pSMBr = NULL;
2739 int bytes_returned;
2740 int name_len, name_len2;
2741 __u16 count;
2742
Joe Perchesf96637b2013-05-04 22:12:25 -05002743 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744copyRetry:
2745 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2746 (void **) &pSMBr);
2747 if (rc)
2748 return rc;
2749
2750 pSMB->BufferFormat = 0x04;
2751 pSMB->Tid2 = target_tid;
2752
2753 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2754
2755 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002756 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2757 fromName, PATH_MAX, nls_codepage,
2758 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 name_len++; /* trailing null */
2760 name_len *= 2;
2761 pSMB->OldFileName[name_len] = 0x04; /* pad */
2762 /* protocol requires ASCII signature byte on Unicode string */
2763 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002764 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002765 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2766 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2768 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002769 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 name_len = strnlen(fromName, PATH_MAX);
2771 name_len++; /* trailing null */
2772 strncpy(pSMB->OldFileName, fromName, name_len);
2773 name_len2 = strnlen(toName, PATH_MAX);
2774 name_len2++; /* trailing null */
2775 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2776 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2777 name_len2++; /* trailing null */
2778 name_len2++; /* signature byte */
2779 }
2780
2781 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002782 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 pSMB->ByteCount = cpu_to_le16(count);
2784
2785 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2786 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2787 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002788 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2789 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 }
Steve French0d817bc2008-05-22 02:02:03 +00002791 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 if (rc == -EAGAIN)
2794 goto copyRetry;
2795
2796 return rc;
2797}
2798
2799int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002800CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002802 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803{
2804 TRANSACTION2_SPI_REQ *pSMB = NULL;
2805 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2806 char *data_offset;
2807 int name_len;
2808 int name_len_target;
2809 int rc = 0;
2810 int bytes_returned = 0;
2811 __u16 params, param_offset, offset, byte_count;
2812
Joe Perchesf96637b2013-05-04 22:12:25 -05002813 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814createSymLinkRetry:
2815 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2816 (void **) &pSMBr);
2817 if (rc)
2818 return rc;
2819
2820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2821 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002822 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2823 /* find define for this maxpathcomponent */
2824 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 name_len++; /* trailing null */
2826 name_len *= 2;
2827
Steve French50c2f752007-07-13 00:33:32 +00002828 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 name_len = strnlen(fromName, PATH_MAX);
2830 name_len++; /* trailing null */
2831 strncpy(pSMB->FileName, fromName, name_len);
2832 }
2833 params = 6 + name_len;
2834 pSMB->MaxSetupCount = 0;
2835 pSMB->Reserved = 0;
2836 pSMB->Flags = 0;
2837 pSMB->Timeout = 0;
2838 pSMB->Reserved2 = 0;
2839 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002840 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 offset = param_offset + params;
2842
2843 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2844 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2845 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002846 cifsConvertToUTF16((__le16 *) data_offset, toName,
2847 /* find define for this maxpathcomponent */
2848 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 name_len_target++; /* trailing null */
2850 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002851 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 name_len_target = strnlen(toName, PATH_MAX);
2853 name_len_target++; /* trailing null */
2854 strncpy(data_offset, toName, name_len_target);
2855 }
2856
2857 pSMB->MaxParameterCount = cpu_to_le16(2);
2858 /* BB find exact max on data count below from sess */
2859 pSMB->MaxDataCount = cpu_to_le16(1000);
2860 pSMB->SetupCount = 1;
2861 pSMB->Reserved3 = 0;
2862 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2863 byte_count = 3 /* pad */ + params + name_len_target;
2864 pSMB->DataCount = cpu_to_le16(name_len_target);
2865 pSMB->ParameterCount = cpu_to_le16(params);
2866 pSMB->TotalDataCount = pSMB->DataCount;
2867 pSMB->TotalParameterCount = pSMB->ParameterCount;
2868 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2869 pSMB->DataOffset = cpu_to_le16(offset);
2870 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2871 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002872 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 pSMB->ByteCount = cpu_to_le16(byte_count);
2874 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2875 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002876 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002877 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002878 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2879 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
Steve French0d817bc2008-05-22 02:02:03 +00002881 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
2883 if (rc == -EAGAIN)
2884 goto createSymLinkRetry;
2885
2886 return rc;
2887}
2888
2889int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002890CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002892 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893{
2894 TRANSACTION2_SPI_REQ *pSMB = NULL;
2895 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2896 char *data_offset;
2897 int name_len;
2898 int name_len_target;
2899 int rc = 0;
2900 int bytes_returned = 0;
2901 __u16 params, param_offset, offset, byte_count;
2902
Joe Perchesf96637b2013-05-04 22:12:25 -05002903 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904createHardLinkRetry:
2905 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2906 (void **) &pSMBr);
2907 if (rc)
2908 return rc;
2909
2910 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002911 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2912 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 name_len++; /* trailing null */
2914 name_len *= 2;
2915
Steve French50c2f752007-07-13 00:33:32 +00002916 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 name_len = strnlen(toName, PATH_MAX);
2918 name_len++; /* trailing null */
2919 strncpy(pSMB->FileName, toName, name_len);
2920 }
2921 params = 6 + name_len;
2922 pSMB->MaxSetupCount = 0;
2923 pSMB->Reserved = 0;
2924 pSMB->Flags = 0;
2925 pSMB->Timeout = 0;
2926 pSMB->Reserved2 = 0;
2927 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002928 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 offset = param_offset + params;
2930
2931 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2933 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002934 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2935 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 name_len_target++; /* trailing null */
2937 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002938 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 name_len_target = strnlen(fromName, PATH_MAX);
2940 name_len_target++; /* trailing null */
2941 strncpy(data_offset, fromName, name_len_target);
2942 }
2943
2944 pSMB->MaxParameterCount = cpu_to_le16(2);
2945 /* BB find exact max on data count below from sess*/
2946 pSMB->MaxDataCount = cpu_to_le16(1000);
2947 pSMB->SetupCount = 1;
2948 pSMB->Reserved3 = 0;
2949 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2950 byte_count = 3 /* pad */ + params + name_len_target;
2951 pSMB->ParameterCount = cpu_to_le16(params);
2952 pSMB->TotalParameterCount = pSMB->ParameterCount;
2953 pSMB->DataCount = cpu_to_le16(name_len_target);
2954 pSMB->TotalDataCount = pSMB->DataCount;
2955 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2956 pSMB->DataOffset = cpu_to_le16(offset);
2957 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2958 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002959 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 pSMB->ByteCount = cpu_to_le16(byte_count);
2961 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2962 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002963 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002964 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002965 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2966 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
2968 cifs_buf_release(pSMB);
2969 if (rc == -EAGAIN)
2970 goto createHardLinkRetry;
2971
2972 return rc;
2973}
2974
2975int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002976CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002977 const char *from_name, const char *to_name,
2978 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979{
2980 int rc = 0;
2981 NT_RENAME_REQ *pSMB = NULL;
2982 RENAME_RSP *pSMBr = NULL;
2983 int bytes_returned;
2984 int name_len, name_len2;
2985 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002986 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
Joe Perchesf96637b2013-05-04 22:12:25 -05002988 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989winCreateHardLinkRetry:
2990
2991 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2992 (void **) &pSMBr);
2993 if (rc)
2994 return rc;
2995
2996 pSMB->SearchAttributes =
2997 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2998 ATTR_DIRECTORY);
2999 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3000 pSMB->ClusterCount = 0;
3001
3002 pSMB->BufferFormat = 0x04;
3003
3004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3005 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003006 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3007 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 name_len++; /* trailing null */
3009 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003010
3011 /* protocol specifies ASCII buffer format (0x04) for unicode */
3012 pSMB->OldFileName[name_len] = 0x04;
3013 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003015 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003016 to_name, PATH_MAX, cifs_sb->local_nls,
3017 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3019 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003020 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003021 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003023 strncpy(pSMB->OldFileName, from_name, name_len);
3024 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 name_len2++; /* trailing null */
3026 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003027 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 name_len2++; /* trailing null */
3029 name_len2++; /* signature byte */
3030 }
3031
3032 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003033 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 pSMB->ByteCount = cpu_to_le16(count);
3035
3036 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003038 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003039 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003040 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003041
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 cifs_buf_release(pSMB);
3043 if (rc == -EAGAIN)
3044 goto winCreateHardLinkRetry;
3045
3046 return rc;
3047}
3048
3049int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003050CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003051 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003052 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053{
3054/* SMB_QUERY_FILE_UNIX_LINK */
3055 TRANSACTION2_QPI_REQ *pSMB = NULL;
3056 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3057 int rc = 0;
3058 int bytes_returned;
3059 int name_len;
3060 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003061 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
Joe Perchesf96637b2013-05-04 22:12:25 -05003063 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
3065querySymLinkRetry:
3066 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3067 (void **) &pSMBr);
3068 if (rc)
3069 return rc;
3070
3071 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3072 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003073 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3074 searchName, PATH_MAX, nls_codepage,
3075 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 name_len++; /* trailing null */
3077 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003078 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 name_len = strnlen(searchName, PATH_MAX);
3080 name_len++; /* trailing null */
3081 strncpy(pSMB->FileName, searchName, name_len);
3082 }
3083
3084 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3085 pSMB->TotalDataCount = 0;
3086 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003087 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 pSMB->MaxSetupCount = 0;
3089 pSMB->Reserved = 0;
3090 pSMB->Flags = 0;
3091 pSMB->Timeout = 0;
3092 pSMB->Reserved2 = 0;
3093 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003094 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 pSMB->DataCount = 0;
3096 pSMB->DataOffset = 0;
3097 pSMB->SetupCount = 1;
3098 pSMB->Reserved3 = 0;
3099 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3100 byte_count = params + 1 /* pad */ ;
3101 pSMB->TotalParameterCount = cpu_to_le16(params);
3102 pSMB->ParameterCount = pSMB->TotalParameterCount;
3103 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3104 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003105 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 pSMB->ByteCount = cpu_to_le16(byte_count);
3107
3108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3109 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3110 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003111 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 } else {
3113 /* decode response */
3114
3115 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003117 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003118 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003120 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003121 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
Jeff Layton460b9692009-04-30 07:17:56 -04003123 data_start = ((char *) &pSMBr->hdr.Protocol) +
3124 le16_to_cpu(pSMBr->t2.DataOffset);
3125
Steve French0e0d2cf2009-05-01 05:27:32 +00003126 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3127 is_unicode = true;
3128 else
3129 is_unicode = false;
3130
Steve French737b7582005-04-28 22:41:06 -07003131 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003132 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3133 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003134 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003135 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 }
3137 }
3138 cifs_buf_release(pSMB);
3139 if (rc == -EAGAIN)
3140 goto querySymLinkRetry;
3141 return rc;
3142}
3143
Steve Frenchc52a9552011-02-24 06:16:22 +00003144/*
3145 * Recent Windows versions now create symlinks more frequently
3146 * and they use the "reparse point" mechanism below. We can of course
3147 * do symlinks nicely to Samba and other servers which support the
3148 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3149 * "MF" symlinks optionally, but for recent Windows we really need to
3150 * reenable the code below and fix the cifs_symlink callers to handle this.
3151 * In the interim this code has been moved to its own config option so
3152 * it is not compiled in by default until callers fixed up and more tested.
3153 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003155CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3156 __u16 fid, char **symlinkinfo,
3157 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158{
3159 int rc = 0;
3160 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003161 struct smb_com_transaction_ioctl_req *pSMB;
3162 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003163 bool is_unicode;
3164 unsigned int sub_len;
3165 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003166 struct reparse_symlink_data *reparse_buf;
3167 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003168 __u32 data_offset, data_count;
3169 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003171 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3173 (void **) &pSMBr);
3174 if (rc)
3175 return rc;
3176
3177 pSMB->TotalParameterCount = 0 ;
3178 pSMB->TotalDataCount = 0;
3179 pSMB->MaxParameterCount = cpu_to_le32(2);
3180 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003181 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 pSMB->MaxSetupCount = 4;
3183 pSMB->Reserved = 0;
3184 pSMB->ParameterOffset = 0;
3185 pSMB->DataCount = 0;
3186 pSMB->DataOffset = 0;
3187 pSMB->SetupCount = 4;
3188 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3189 pSMB->ParameterCount = pSMB->TotalParameterCount;
3190 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3191 pSMB->IsFsctl = 1; /* FSCTL */
3192 pSMB->IsRootFlag = 0;
3193 pSMB->Fid = fid; /* file handle always le */
3194 pSMB->ByteCount = 0;
3195
3196 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3198 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003199 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003200 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
Steve French989c7e52009-05-02 05:32:20 +00003202
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003203 data_offset = le32_to_cpu(pSMBr->DataOffset);
3204 data_count = le32_to_cpu(pSMBr->DataCount);
3205 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3206 /* BB also check enough total bytes returned */
3207 rc = -EIO; /* bad smb */
3208 goto qreparse_out;
3209 }
3210 if (!data_count || (data_count > 2048)) {
3211 rc = -EIO;
3212 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3213 goto qreparse_out;
3214 }
3215 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003216 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003217 ((char *)&pSMBr->hdr.Protocol + data_offset);
3218 if ((char *)reparse_buf >= end_of_smb) {
3219 rc = -EIO;
3220 goto qreparse_out;
3221 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003222 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3223 cifs_dbg(FYI, "NFS style reparse tag\n");
3224 posix_buf = (struct reparse_posix_data *)reparse_buf;
3225
3226 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3227 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3228 le64_to_cpu(posix_buf->InodeType));
3229 rc = -EOPNOTSUPP;
3230 goto qreparse_out;
3231 }
3232 is_unicode = true;
3233 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3234 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3235 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3236 rc = -EIO;
3237 goto qreparse_out;
3238 }
3239 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3240 sub_len, is_unicode, nls_codepage);
3241 goto qreparse_out;
3242 } else if (reparse_buf->ReparseTag !=
3243 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3244 rc = -EOPNOTSUPP;
3245 goto qreparse_out;
3246 }
3247
3248 /* Reparse tag is NTFS symlink */
3249 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3250 reparse_buf->PathBuffer;
3251 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3252 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003253 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3254 rc = -EIO;
3255 goto qreparse_out;
3256 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003257 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3258 is_unicode = true;
3259 else
3260 is_unicode = false;
3261
3262 /* BB FIXME investigate remapping reserved chars here */
3263 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3264 nls_codepage);
3265 if (!*symlinkinfo)
3266 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003268 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003270 /*
3271 * Note: On -EAGAIN error only caller can retry on handle based calls
3272 * since file handle passed in no longer valid.
3273 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 return rc;
3275}
3276
Steve Frenchc7f508a2013-10-14 15:27:32 -05003277int
3278CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3279 __u16 fid)
3280{
3281 int rc = 0;
3282 int bytes_returned;
3283 struct smb_com_transaction_compr_ioctl_req *pSMB;
3284 struct smb_com_transaction_ioctl_rsp *pSMBr;
3285
3286 cifs_dbg(FYI, "Set compression for %u\n", fid);
3287 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3288 (void **) &pSMBr);
3289 if (rc)
3290 return rc;
3291
3292 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3293
3294 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003295 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003296 pSMB->MaxParameterCount = 0;
3297 pSMB->MaxDataCount = 0;
3298 pSMB->MaxSetupCount = 4;
3299 pSMB->Reserved = 0;
3300 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003301 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003302 pSMB->DataOffset =
3303 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3304 compression_state) - 4); /* 84 */
3305 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003306 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003307 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003308 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003309 pSMB->IsFsctl = 1; /* FSCTL */
3310 pSMB->IsRootFlag = 0;
3311 pSMB->Fid = fid; /* file handle always le */
3312 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003313 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003314 inc_rfc1001_len(pSMB, 5);
3315
3316 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3317 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3318 if (rc)
3319 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3320
3321 cifs_buf_release(pSMB);
3322
3323 /*
3324 * Note: On -EAGAIN error only caller can retry on handle based calls
3325 * since file handle passed in no longer valid.
3326 */
3327 return rc;
3328}
3329
3330
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331#ifdef CONFIG_CIFS_POSIX
3332
3333/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003334static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003335 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336{
3337 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003338 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3339 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3340 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003341/*
3342 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3343 ace->e_perm, ace->e_tag, ace->e_id);
3344*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
3346 return;
3347}
3348
3349/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003350static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3351 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352{
3353 int size = 0;
3354 int i;
3355 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003356 struct cifs_posix_ace *pACE;
3357 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003358 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
3360 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3361 return -EOPNOTSUPP;
3362
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003363 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 count = le16_to_cpu(cifs_acl->access_entry_count);
3365 pACE = &cifs_acl->ace_array[0];
3366 size = sizeof(struct cifs_posix_acl);
3367 size += sizeof(struct cifs_posix_ace) * count;
3368 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003369 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003370 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3371 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 return -EINVAL;
3373 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003374 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 count = le16_to_cpu(cifs_acl->access_entry_count);
3376 size = sizeof(struct cifs_posix_acl);
3377 size += sizeof(struct cifs_posix_ace) * count;
3378/* skip past access ACEs to get to default ACEs */
3379 pACE = &cifs_acl->ace_array[count];
3380 count = le16_to_cpu(cifs_acl->default_entry_count);
3381 size += sizeof(struct cifs_posix_ace) * count;
3382 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003383 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 return -EINVAL;
3385 } else {
3386 /* illegal type */
3387 return -EINVAL;
3388 }
3389
3390 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003391 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003392 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003393 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 return -ERANGE;
3395 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003396 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3397
Steve Frenchff7feac2005-11-15 16:45:16 -08003398 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003399 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003400 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003401 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 }
3403 }
3404 return size;
3405}
3406
Steve French50c2f752007-07-13 00:33:32 +00003407static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003408 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409{
3410 __u16 rc = 0; /* 0 = ACL converted ok */
3411
Steve Frenchff7feac2005-11-15 16:45:16 -08003412 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3413 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003415 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 /* Probably no need to le convert -1 on any arch but can not hurt */
3417 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003418 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003419 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003420/*
3421 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3422 ace->e_perm, ace->e_tag, ace->e_id);
3423*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 return rc;
3425}
3426
3427/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003428static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3429 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430{
3431 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003432 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003433 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003434 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 int count;
3436 int i;
3437
Steve French790fe572007-07-07 19:25:05 +00003438 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 return 0;
3440
3441 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003442 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3443 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003444 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003445 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3446 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 return 0;
3448 }
3449 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003450 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003451 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003452 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003453 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003454 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003455 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003456 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003457 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 return 0;
3459 }
Steve French50c2f752007-07-13 00:33:32 +00003460 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003461 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003462 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 /* ACE not converted */
3464 break;
3465 }
3466 }
Steve French790fe572007-07-07 19:25:05 +00003467 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3469 rc += sizeof(struct cifs_posix_acl);
3470 /* BB add check to make sure ACL does not overflow SMB */
3471 }
3472 return rc;
3473}
3474
3475int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003476CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003477 const unsigned char *searchName,
3478 char *acl_inf, const int buflen, const int acl_type,
3479 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480{
3481/* SMB_QUERY_POSIX_ACL */
3482 TRANSACTION2_QPI_REQ *pSMB = NULL;
3483 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3484 int rc = 0;
3485 int bytes_returned;
3486 int name_len;
3487 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003488
Joe Perchesf96637b2013-05-04 22:12:25 -05003489 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
3491queryAclRetry:
3492 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3493 (void **) &pSMBr);
3494 if (rc)
3495 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003496
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3498 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003499 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3500 searchName, PATH_MAX, nls_codepage,
3501 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 name_len++; /* trailing null */
3503 name_len *= 2;
3504 pSMB->FileName[name_len] = 0;
3505 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003506 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 name_len = strnlen(searchName, PATH_MAX);
3508 name_len++; /* trailing null */
3509 strncpy(pSMB->FileName, searchName, name_len);
3510 }
3511
3512 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3513 pSMB->TotalDataCount = 0;
3514 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003515 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 pSMB->MaxDataCount = cpu_to_le16(4000);
3517 pSMB->MaxSetupCount = 0;
3518 pSMB->Reserved = 0;
3519 pSMB->Flags = 0;
3520 pSMB->Timeout = 0;
3521 pSMB->Reserved2 = 0;
3522 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003523 offsetof(struct smb_com_transaction2_qpi_req,
3524 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 pSMB->DataCount = 0;
3526 pSMB->DataOffset = 0;
3527 pSMB->SetupCount = 1;
3528 pSMB->Reserved3 = 0;
3529 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3530 byte_count = params + 1 /* pad */ ;
3531 pSMB->TotalParameterCount = cpu_to_le16(params);
3532 pSMB->ParameterCount = pSMB->TotalParameterCount;
3533 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3534 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003535 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 pSMB->ByteCount = cpu_to_le16(byte_count);
3537
3538 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3539 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003540 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003542 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 } else {
3544 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003545
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003548 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 rc = -EIO; /* bad smb */
3550 else {
3551 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3552 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3553 rc = cifs_copy_posix_acl(acl_inf,
3554 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003555 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 }
3557 }
3558 cifs_buf_release(pSMB);
3559 if (rc == -EAGAIN)
3560 goto queryAclRetry;
3561 return rc;
3562}
3563
3564int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003565CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003566 const unsigned char *fileName,
3567 const char *local_acl, const int buflen,
3568 const int acl_type,
3569 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570{
3571 struct smb_com_transaction2_spi_req *pSMB = NULL;
3572 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3573 char *parm_data;
3574 int name_len;
3575 int rc = 0;
3576 int bytes_returned = 0;
3577 __u16 params, byte_count, data_count, param_offset, offset;
3578
Joe Perchesf96637b2013-05-04 22:12:25 -05003579 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580setAclRetry:
3581 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003582 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 if (rc)
3584 return rc;
3585 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3586 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003587 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3588 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 name_len++; /* trailing null */
3590 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003591 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 name_len = strnlen(fileName, PATH_MAX);
3593 name_len++; /* trailing null */
3594 strncpy(pSMB->FileName, fileName, name_len);
3595 }
3596 params = 6 + name_len;
3597 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003598 /* BB find max SMB size from sess */
3599 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 pSMB->MaxSetupCount = 0;
3601 pSMB->Reserved = 0;
3602 pSMB->Flags = 0;
3603 pSMB->Timeout = 0;
3604 pSMB->Reserved2 = 0;
3605 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003606 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 offset = param_offset + params;
3608 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3609 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3610
3611 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003612 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613
Steve French790fe572007-07-07 19:25:05 +00003614 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 rc = -EOPNOTSUPP;
3616 goto setACLerrorExit;
3617 }
3618 pSMB->DataOffset = cpu_to_le16(offset);
3619 pSMB->SetupCount = 1;
3620 pSMB->Reserved3 = 0;
3621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3622 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3623 byte_count = 3 /* pad */ + params + data_count;
3624 pSMB->DataCount = cpu_to_le16(data_count);
3625 pSMB->TotalDataCount = pSMB->DataCount;
3626 pSMB->ParameterCount = cpu_to_le16(params);
3627 pSMB->TotalParameterCount = pSMB->ParameterCount;
3628 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003629 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 pSMB->ByteCount = cpu_to_le16(byte_count);
3631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003633 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003634 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635
3636setACLerrorExit:
3637 cifs_buf_release(pSMB);
3638 if (rc == -EAGAIN)
3639 goto setAclRetry;
3640 return rc;
3641}
3642
Steve Frenchf654bac2005-04-28 22:41:04 -07003643/* BB fix tabs in this function FIXME BB */
3644int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003645CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003646 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003647{
Steve French50c2f752007-07-13 00:33:32 +00003648 int rc = 0;
3649 struct smb_t2_qfi_req *pSMB = NULL;
3650 struct smb_t2_qfi_rsp *pSMBr = NULL;
3651 int bytes_returned;
3652 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003653
Joe Perchesf96637b2013-05-04 22:12:25 -05003654 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003655 if (tcon == NULL)
3656 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003657
3658GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003659 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3660 (void **) &pSMBr);
3661 if (rc)
3662 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003663
Steve Frenchad7a2922008-02-07 23:25:02 +00003664 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003665 pSMB->t2.TotalDataCount = 0;
3666 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3667 /* BB find exact max data count below from sess structure BB */
3668 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3669 pSMB->t2.MaxSetupCount = 0;
3670 pSMB->t2.Reserved = 0;
3671 pSMB->t2.Flags = 0;
3672 pSMB->t2.Timeout = 0;
3673 pSMB->t2.Reserved2 = 0;
3674 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3675 Fid) - 4);
3676 pSMB->t2.DataCount = 0;
3677 pSMB->t2.DataOffset = 0;
3678 pSMB->t2.SetupCount = 1;
3679 pSMB->t2.Reserved3 = 0;
3680 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3681 byte_count = params + 1 /* pad */ ;
3682 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3683 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3684 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3685 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003686 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003687 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003688 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003689
Steve French790fe572007-07-07 19:25:05 +00003690 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3691 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3692 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003693 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003694 } else {
3695 /* decode response */
3696 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003697 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003698 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003699 /* If rc should we check for EOPNOSUPP and
3700 disable the srvino flag? or in caller? */
3701 rc = -EIO; /* bad smb */
3702 else {
3703 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3704 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3705 struct file_chattr_info *pfinfo;
3706 /* BB Do we need a cast or hash here ? */
3707 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003708 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003709 rc = -EIO;
3710 goto GetExtAttrOut;
3711 }
3712 pfinfo = (struct file_chattr_info *)
3713 (data_offset + (char *) &pSMBr->hdr.Protocol);
3714 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003715 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003716 }
3717 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003718GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003719 cifs_buf_release(pSMB);
3720 if (rc == -EAGAIN)
3721 goto GetExtAttrRetry;
3722 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003723}
3724
Steve Frenchf654bac2005-04-28 22:41:04 -07003725#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726
Jeff Layton79df1ba2010-12-06 12:52:08 -05003727#ifdef CONFIG_CIFS_ACL
3728/*
3729 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3730 * all NT TRANSACTS that we init here have total parm and data under about 400
3731 * bytes (to fit in small cifs buffer size), which is the case so far, it
3732 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3733 * returned setup area) and MaxParameterCount (returned parms size) must be set
3734 * by caller
3735 */
3736static int
3737smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003738 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003739 void **ret_buf)
3740{
3741 int rc;
3742 __u32 temp_offset;
3743 struct smb_com_ntransact_req *pSMB;
3744
3745 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3746 (void **)&pSMB);
3747 if (rc)
3748 return rc;
3749 *ret_buf = (void *)pSMB;
3750 pSMB->Reserved = 0;
3751 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3752 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003753 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003754 pSMB->ParameterCount = pSMB->TotalParameterCount;
3755 pSMB->DataCount = pSMB->TotalDataCount;
3756 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3757 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3758 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3759 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3760 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3761 pSMB->SubCommand = cpu_to_le16(sub_command);
3762 return 0;
3763}
3764
3765static int
3766validate_ntransact(char *buf, char **ppparm, char **ppdata,
3767 __u32 *pparmlen, __u32 *pdatalen)
3768{
3769 char *end_of_smb;
3770 __u32 data_count, data_offset, parm_count, parm_offset;
3771 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003772 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003773
3774 *pdatalen = 0;
3775 *pparmlen = 0;
3776
3777 if (buf == NULL)
3778 return -EINVAL;
3779
3780 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3781
Jeff Layton820a8032011-05-04 08:05:26 -04003782 bcc = get_bcc(&pSMBr->hdr);
3783 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003784 (char *)&pSMBr->ByteCount;
3785
3786 data_offset = le32_to_cpu(pSMBr->DataOffset);
3787 data_count = le32_to_cpu(pSMBr->DataCount);
3788 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3789 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3790
3791 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3792 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3793
3794 /* should we also check that parm and data areas do not overlap? */
3795 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003796 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003797 return -EINVAL;
3798 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003799 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003800 return -EINVAL;
3801 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003802 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003803 return -EINVAL;
3804 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003805 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3806 *ppdata, data_count, (data_count + *ppdata),
3807 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003808 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003809 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003810 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003811 return -EINVAL;
3812 }
3813 *pdatalen = data_count;
3814 *pparmlen = parm_count;
3815 return 0;
3816}
3817
Steve French0a4b92c2006-01-12 15:44:21 -08003818/* Get Security Descriptor (by handle) from remote server for a file or dir */
3819int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003820CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003821 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003822{
3823 int rc = 0;
3824 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003825 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003826 struct kvec iov[1];
3827
Joe Perchesf96637b2013-05-04 22:12:25 -05003828 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003829
Steve French630f3f0c2007-10-25 21:17:17 +00003830 *pbuflen = 0;
3831 *acl_inf = NULL;
3832
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003833 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003834 8 /* parm len */, tcon, (void **) &pSMB);
3835 if (rc)
3836 return rc;
3837
3838 pSMB->MaxParameterCount = cpu_to_le32(4);
3839 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3840 pSMB->MaxSetupCount = 0;
3841 pSMB->Fid = fid; /* file handle always le */
3842 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3843 CIFS_ACL_DACL);
3844 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003845 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003846 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003847 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003848
Steve Frencha761ac52007-10-18 21:45:27 +00003849 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003850 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003851 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003852 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003853 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003854 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003855 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003856 __u32 parm_len;
3857 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003858 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003859 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003860
3861/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003862 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003863 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003864 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003865 goto qsec_out;
3866 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3867
Joe Perchesf96637b2013-05-04 22:12:25 -05003868 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3869 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003870
3871 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3872 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003873 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003874 goto qsec_out;
3875 }
3876
3877/* BB check that data area is minimum length and as big as acl_len */
3878
Steve Frenchaf6f4612007-10-16 18:40:37 +00003879 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003880 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003881 cifs_dbg(VFS, "acl length %d does not match %d\n",
3882 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003883 if (*pbuflen > acl_len)
3884 *pbuflen = acl_len;
3885 }
Steve French0a4b92c2006-01-12 15:44:21 -08003886
Steve French630f3f0c2007-10-25 21:17:17 +00003887 /* check if buffer is big enough for the acl
3888 header followed by the smallest SID */
3889 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3890 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003891 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003892 rc = -EINVAL;
3893 *pbuflen = 0;
3894 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003895 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003896 if (*acl_inf == NULL) {
3897 *pbuflen = 0;
3898 rc = -ENOMEM;
3899 }
Steve French630f3f0c2007-10-25 21:17:17 +00003900 }
Steve French0a4b92c2006-01-12 15:44:21 -08003901 }
3902qsec_out:
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01003903 free_rsp_buf(buf_type, iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003904/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003905 return rc;
3906}
Steve French97837582007-12-31 07:47:21 +00003907
3908int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003909CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003910 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003911{
3912 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3913 int rc = 0;
3914 int bytes_returned = 0;
3915 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003916 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003917
3918setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003919 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003920 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003921 return rc;
Steve French97837582007-12-31 07:47:21 +00003922
3923 pSMB->MaxSetupCount = 0;
3924 pSMB->Reserved = 0;
3925
3926 param_count = 8;
3927 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3928 data_count = acllen;
3929 data_offset = param_offset + param_count;
3930 byte_count = 3 /* pad */ + param_count;
3931
3932 pSMB->DataCount = cpu_to_le32(data_count);
3933 pSMB->TotalDataCount = pSMB->DataCount;
3934 pSMB->MaxParameterCount = cpu_to_le32(4);
3935 pSMB->MaxDataCount = cpu_to_le32(16384);
3936 pSMB->ParameterCount = cpu_to_le32(param_count);
3937 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3938 pSMB->TotalParameterCount = pSMB->ParameterCount;
3939 pSMB->DataOffset = cpu_to_le32(data_offset);
3940 pSMB->SetupCount = 0;
3941 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3942 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3943
3944 pSMB->Fid = fid; /* file handle always le */
3945 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003946 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003947
3948 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003949 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3950 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003951 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003952 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003953 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003954
3955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3957
Joe Perchesf96637b2013-05-04 22:12:25 -05003958 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3959 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003960 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003961 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003962 cifs_buf_release(pSMB);
3963
3964 if (rc == -EAGAIN)
3965 goto setCifsAclRetry;
3966
3967 return (rc);
3968}
3969
Jeff Layton79df1ba2010-12-06 12:52:08 -05003970#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003971
Steve French6b8edfe2005-08-23 20:26:03 -07003972/* Legacy Query Path Information call for lookup to old servers such
3973 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003974int
3975SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3976 const char *search_name, FILE_ALL_INFO *data,
3977 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003978{
Steve Frenchad7a2922008-02-07 23:25:02 +00003979 QUERY_INFORMATION_REQ *pSMB;
3980 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003981 int rc = 0;
3982 int bytes_returned;
3983 int name_len;
3984
Joe Perchesf96637b2013-05-04 22:12:25 -05003985 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003986QInfRetry:
3987 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003988 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003989 if (rc)
3990 return rc;
3991
3992 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3993 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003994 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003995 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003996 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003997 name_len++; /* trailing null */
3998 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003999 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004000 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004001 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004002 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004003 }
4004 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004005 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004006 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004007 pSMB->ByteCount = cpu_to_le16(name_len);
4008
4009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004011 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004012 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004013 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004014 struct timespec ts;
4015 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004016
4017 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004018 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004019 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004020 ts.tv_nsec = 0;
4021 ts.tv_sec = time;
4022 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004023 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4024 data->LastWriteTime = data->ChangeTime;
4025 data->LastAccessTime = 0;
4026 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004027 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004028 data->EndOfFile = data->AllocationSize;
4029 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004030 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004031 } else
4032 rc = -EIO; /* bad buffer passed in */
4033
4034 cifs_buf_release(pSMB);
4035
4036 if (rc == -EAGAIN)
4037 goto QInfRetry;
4038
4039 return rc;
4040}
4041
Jeff Laytonbcd53572010-02-12 07:44:16 -05004042int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004043CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004044 u16 netfid, FILE_ALL_INFO *pFindData)
4045{
4046 struct smb_t2_qfi_req *pSMB = NULL;
4047 struct smb_t2_qfi_rsp *pSMBr = NULL;
4048 int rc = 0;
4049 int bytes_returned;
4050 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004051
Jeff Laytonbcd53572010-02-12 07:44:16 -05004052QFileInfoRetry:
4053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4054 (void **) &pSMBr);
4055 if (rc)
4056 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004057
Jeff Laytonbcd53572010-02-12 07:44:16 -05004058 params = 2 /* level */ + 2 /* fid */;
4059 pSMB->t2.TotalDataCount = 0;
4060 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4061 /* BB find exact max data count below from sess structure BB */
4062 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4063 pSMB->t2.MaxSetupCount = 0;
4064 pSMB->t2.Reserved = 0;
4065 pSMB->t2.Flags = 0;
4066 pSMB->t2.Timeout = 0;
4067 pSMB->t2.Reserved2 = 0;
4068 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4069 Fid) - 4);
4070 pSMB->t2.DataCount = 0;
4071 pSMB->t2.DataOffset = 0;
4072 pSMB->t2.SetupCount = 1;
4073 pSMB->t2.Reserved3 = 0;
4074 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4075 byte_count = params + 1 /* pad */ ;
4076 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4077 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4078 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4079 pSMB->Pad = 0;
4080 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004081 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004082 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004083
4084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4086 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004087 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004088 } else { /* decode response */
4089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4090
4091 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4092 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004093 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004094 rc = -EIO; /* bad smb */
4095 else if (pFindData) {
4096 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4097 memcpy((char *) pFindData,
4098 (char *) &pSMBr->hdr.Protocol +
4099 data_offset, sizeof(FILE_ALL_INFO));
4100 } else
4101 rc = -ENOMEM;
4102 }
4103 cifs_buf_release(pSMB);
4104 if (rc == -EAGAIN)
4105 goto QFileInfoRetry;
4106
4107 return rc;
4108}
Steve French6b8edfe2005-08-23 20:26:03 -07004109
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004111CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004112 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004113 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004114 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004116 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 TRANSACTION2_QPI_REQ *pSMB = NULL;
4118 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4119 int rc = 0;
4120 int bytes_returned;
4121 int name_len;
4122 __u16 params, byte_count;
4123
Joe Perchesf96637b2013-05-04 22:12:25 -05004124 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125QPathInfoRetry:
4126 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4127 (void **) &pSMBr);
4128 if (rc)
4129 return rc;
4130
4131 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4132 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004133 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004134 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 name_len++; /* trailing null */
4136 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004137 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004138 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004140 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 }
4142
Steve French50c2f752007-07-13 00:33:32 +00004143 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 pSMB->TotalDataCount = 0;
4145 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004146 /* BB find exact max SMB PDU from sess structure BB */
4147 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 pSMB->MaxSetupCount = 0;
4149 pSMB->Reserved = 0;
4150 pSMB->Flags = 0;
4151 pSMB->Timeout = 0;
4152 pSMB->Reserved2 = 0;
4153 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004154 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 pSMB->DataCount = 0;
4156 pSMB->DataOffset = 0;
4157 pSMB->SetupCount = 1;
4158 pSMB->Reserved3 = 0;
4159 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4160 byte_count = params + 1 /* pad */ ;
4161 pSMB->TotalParameterCount = cpu_to_le16(params);
4162 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004163 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004164 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4165 else
4166 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004168 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 pSMB->ByteCount = cpu_to_le16(byte_count);
4170
4171 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4172 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4173 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004174 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 } else { /* decode response */
4176 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4177
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004178 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4179 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004180 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004182 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004183 rc = -EIO; /* 24 or 26 expected but we do not read
4184 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004185 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004186 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004188
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004189 /*
4190 * On legacy responses we do not read the last field,
4191 * EAsize, fortunately since it varies by subdialect and
4192 * also note it differs on Set vs Get, ie two bytes or 4
4193 * bytes depending but we don't care here.
4194 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004195 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004196 size = sizeof(FILE_INFO_STANDARD);
4197 else
4198 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004199 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004200 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 } else
4202 rc = -ENOMEM;
4203 }
4204 cifs_buf_release(pSMB);
4205 if (rc == -EAGAIN)
4206 goto QPathInfoRetry;
4207
4208 return rc;
4209}
4210
4211int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004212CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004213 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4214{
4215 struct smb_t2_qfi_req *pSMB = NULL;
4216 struct smb_t2_qfi_rsp *pSMBr = NULL;
4217 int rc = 0;
4218 int bytes_returned;
4219 __u16 params, byte_count;
4220
4221UnixQFileInfoRetry:
4222 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4223 (void **) &pSMBr);
4224 if (rc)
4225 return rc;
4226
4227 params = 2 /* level */ + 2 /* fid */;
4228 pSMB->t2.TotalDataCount = 0;
4229 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4230 /* BB find exact max data count below from sess structure BB */
4231 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4232 pSMB->t2.MaxSetupCount = 0;
4233 pSMB->t2.Reserved = 0;
4234 pSMB->t2.Flags = 0;
4235 pSMB->t2.Timeout = 0;
4236 pSMB->t2.Reserved2 = 0;
4237 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4238 Fid) - 4);
4239 pSMB->t2.DataCount = 0;
4240 pSMB->t2.DataOffset = 0;
4241 pSMB->t2.SetupCount = 1;
4242 pSMB->t2.Reserved3 = 0;
4243 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4244 byte_count = params + 1 /* pad */ ;
4245 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4246 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4247 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4248 pSMB->Pad = 0;
4249 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004250 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004251 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004252
4253 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4254 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4255 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004256 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004257 } else { /* decode response */
4258 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4259
Jeff Layton820a8032011-05-04 08:05:26 -04004260 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004261 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 -05004262 rc = -EIO; /* bad smb */
4263 } else {
4264 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4265 memcpy((char *) pFindData,
4266 (char *) &pSMBr->hdr.Protocol +
4267 data_offset,
4268 sizeof(FILE_UNIX_BASIC_INFO));
4269 }
4270 }
4271
4272 cifs_buf_release(pSMB);
4273 if (rc == -EAGAIN)
4274 goto UnixQFileInfoRetry;
4275
4276 return rc;
4277}
4278
4279int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004280CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004282 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004283 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284{
4285/* SMB_QUERY_FILE_UNIX_BASIC */
4286 TRANSACTION2_QPI_REQ *pSMB = NULL;
4287 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4288 int rc = 0;
4289 int bytes_returned = 0;
4290 int name_len;
4291 __u16 params, byte_count;
4292
Joe Perchesf96637b2013-05-04 22:12:25 -05004293 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294UnixQPathInfoRetry:
4295 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4296 (void **) &pSMBr);
4297 if (rc)
4298 return rc;
4299
4300 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4301 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004302 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4303 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 name_len++; /* trailing null */
4305 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004306 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 name_len = strnlen(searchName, PATH_MAX);
4308 name_len++; /* trailing null */
4309 strncpy(pSMB->FileName, searchName, name_len);
4310 }
4311
Steve French50c2f752007-07-13 00:33:32 +00004312 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 pSMB->TotalDataCount = 0;
4314 pSMB->MaxParameterCount = cpu_to_le16(2);
4315 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004316 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 pSMB->MaxSetupCount = 0;
4318 pSMB->Reserved = 0;
4319 pSMB->Flags = 0;
4320 pSMB->Timeout = 0;
4321 pSMB->Reserved2 = 0;
4322 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004323 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 pSMB->DataCount = 0;
4325 pSMB->DataOffset = 0;
4326 pSMB->SetupCount = 1;
4327 pSMB->Reserved3 = 0;
4328 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4329 byte_count = params + 1 /* pad */ ;
4330 pSMB->TotalParameterCount = cpu_to_le16(params);
4331 pSMB->ParameterCount = pSMB->TotalParameterCount;
4332 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4333 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004334 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 pSMB->ByteCount = cpu_to_le16(byte_count);
4336
4337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4339 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004340 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 } else { /* decode response */
4342 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4343
Jeff Layton820a8032011-05-04 08:05:26 -04004344 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004345 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 -07004346 rc = -EIO; /* bad smb */
4347 } else {
4348 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4349 memcpy((char *) pFindData,
4350 (char *) &pSMBr->hdr.Protocol +
4351 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004352 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 }
4354 }
4355 cifs_buf_release(pSMB);
4356 if (rc == -EAGAIN)
4357 goto UnixQPathInfoRetry;
4358
4359 return rc;
4360}
4361
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362/* xid, tcon, searchName and codepage are input parms, rest are returned */
4363int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004364CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004365 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004366 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004367 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368{
4369/* level 257 SMB_ */
4370 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4371 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004372 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 int rc = 0;
4374 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004375 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004377 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378
Joe Perchesf96637b2013-05-04 22:12:25 -05004379 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
4381findFirstRetry:
4382 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4383 (void **) &pSMBr);
4384 if (rc)
4385 return rc;
4386
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004387 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004388 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004389
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4391 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004392 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4393 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004394 /* We can not add the asterik earlier in case
4395 it got remapped to 0xF03A as if it were part of the
4396 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004398 if (msearch) {
4399 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4400 pSMB->FileName[name_len+1] = 0;
4401 pSMB->FileName[name_len+2] = '*';
4402 pSMB->FileName[name_len+3] = 0;
4403 name_len += 4; /* now the trailing null */
4404 /* null terminate just in case */
4405 pSMB->FileName[name_len] = 0;
4406 pSMB->FileName[name_len+1] = 0;
4407 name_len += 2;
4408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 } else { /* BB add check for overrun of SMB buf BB */
4410 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004412 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 free buffer exit; BB */
4414 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004415 if (msearch) {
4416 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4417 pSMB->FileName[name_len+1] = '*';
4418 pSMB->FileName[name_len+2] = 0;
4419 name_len += 3;
4420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 }
4422
4423 params = 12 + name_len /* includes null */ ;
4424 pSMB->TotalDataCount = 0; /* no EAs */
4425 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004426 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 pSMB->MaxSetupCount = 0;
4428 pSMB->Reserved = 0;
4429 pSMB->Flags = 0;
4430 pSMB->Timeout = 0;
4431 pSMB->Reserved2 = 0;
4432 byte_count = params + 1 /* pad */ ;
4433 pSMB->TotalParameterCount = cpu_to_le16(params);
4434 pSMB->ParameterCount = pSMB->TotalParameterCount;
4435 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004436 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4437 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 pSMB->DataCount = 0;
4439 pSMB->DataOffset = 0;
4440 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4441 pSMB->Reserved3 = 0;
4442 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4443 pSMB->SearchAttributes =
4444 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4445 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004446 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004447 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4449
4450 /* BB what should we set StorageType to? Does it matter? BB */
4451 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004452 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 pSMB->ByteCount = cpu_to_le16(byte_count);
4454
4455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004457 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
Steve French88274812006-03-09 22:21:45 +00004459 if (rc) {/* BB add logic to retry regular search if Unix search
4460 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004462 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004463
Steve French88274812006-03-09 22:21:45 +00004464 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
4466 /* BB eventually could optimize out free and realloc of buf */
4467 /* for this case */
4468 if (rc == -EAGAIN)
4469 goto findFirstRetry;
4470 } else { /* decode response */
4471 /* BB remember to free buffer if error BB */
4472 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004473 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004474 unsigned int lnoff;
4475
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004477 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 else
Steve French4b18f2a2008-04-29 00:06:05 +00004479 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480
4481 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004482 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004483 psrch_inf->srch_entries_start =
4484 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4487 le16_to_cpu(pSMBr->t2.ParameterOffset));
4488
Steve French790fe572007-07-07 19:25:05 +00004489 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004490 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 else
Steve French4b18f2a2008-04-29 00:06:05 +00004492 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
Steve French50c2f752007-07-13 00:33:32 +00004494 psrch_inf->entries_in_buffer =
4495 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004496 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004498 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004499 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004500 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004501 psrch_inf->last_entry = NULL;
4502 return rc;
4503 }
4504
Steve French0752f152008-10-07 20:03:33 +00004505 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004506 lnoff;
4507
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004508 if (pnetfid)
4509 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 } else {
4511 cifs_buf_release(pSMB);
4512 }
4513 }
4514
4515 return rc;
4516}
4517
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004518int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4519 __u16 searchHandle, __u16 search_flags,
4520 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521{
4522 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4523 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004524 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 char *response_data;
4526 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004527 int bytes_returned;
4528 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 __u16 params, byte_count;
4530
Joe Perchesf96637b2013-05-04 22:12:25 -05004531 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Steve French4b18f2a2008-04-29 00:06:05 +00004533 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 return -ENOENT;
4535
4536 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4537 (void **) &pSMBr);
4538 if (rc)
4539 return rc;
4540
Steve French50c2f752007-07-13 00:33:32 +00004541 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 byte_count = 0;
4543 pSMB->TotalDataCount = 0; /* no EAs */
4544 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004545 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 pSMB->MaxSetupCount = 0;
4547 pSMB->Reserved = 0;
4548 pSMB->Flags = 0;
4549 pSMB->Timeout = 0;
4550 pSMB->Reserved2 = 0;
4551 pSMB->ParameterOffset = cpu_to_le16(
4552 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4553 pSMB->DataCount = 0;
4554 pSMB->DataOffset = 0;
4555 pSMB->SetupCount = 1;
4556 pSMB->Reserved3 = 0;
4557 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4558 pSMB->SearchHandle = searchHandle; /* always kept as le */
4559 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004560 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4562 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004563 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
4565 name_len = psrch_inf->resume_name_len;
4566 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004567 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4569 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004570 /* 14 byte parm len above enough for 2 byte null terminator */
4571 pSMB->ResumeFileName[name_len] = 0;
4572 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 } else {
4574 rc = -EINVAL;
4575 goto FNext2_err_exit;
4576 }
4577 byte_count = params + 1 /* pad */ ;
4578 pSMB->TotalParameterCount = cpu_to_le16(params);
4579 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004580 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004582
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004585 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 if (rc) {
4587 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004588 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004589 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004590 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004592 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 } else { /* decode response */
4594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004595
Steve French790fe572007-07-07 19:25:05 +00004596 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004597 unsigned int lnoff;
4598
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 /* BB fixme add lock for file (srch_info) struct here */
4600 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004601 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 else
Steve French4b18f2a2008-04-29 00:06:05 +00004603 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 response_data = (char *) &pSMBr->hdr.Protocol +
4605 le16_to_cpu(pSMBr->t2.ParameterOffset);
4606 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4607 response_data = (char *)&pSMBr->hdr.Protocol +
4608 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004609 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004610 cifs_small_buf_release(
4611 psrch_inf->ntwrk_buf_start);
4612 else
4613 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 psrch_inf->srch_entries_start = response_data;
4615 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004616 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004617 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004618 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 else
Steve French4b18f2a2008-04-29 00:06:05 +00004620 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004621 psrch_inf->entries_in_buffer =
4622 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 psrch_inf->index_of_last_entry +=
4624 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004625 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004626 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004627 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004628 psrch_inf->last_entry = NULL;
4629 return rc;
4630 } else
4631 psrch_inf->last_entry =
4632 psrch_inf->srch_entries_start + lnoff;
4633
Joe Perchesf96637b2013-05-04 22:12:25 -05004634/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4635 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
4637 /* BB fixme add unlock here */
4638 }
4639
4640 }
4641
4642 /* BB On error, should we leave previous search buf (and count and
4643 last entry fields) intact or free the previous one? */
4644
4645 /* Note: On -EAGAIN error only caller can retry on handle based calls
4646 since file handle passed in no longer valid */
4647FNext2_err_exit:
4648 if (rc != 0)
4649 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 return rc;
4651}
4652
4653int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004654CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004655 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656{
4657 int rc = 0;
4658 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659
Joe Perchesf96637b2013-05-04 22:12:25 -05004660 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4662
4663 /* no sense returning error if session restarted
4664 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004665 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 return 0;
4667 if (rc)
4668 return rc;
4669
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 pSMB->FileID = searchHandle;
4671 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004672 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004673 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004674 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004675
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004676 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677
4678 /* Since session is dead, search handle closed on server already */
4679 if (rc == -EAGAIN)
4680 rc = 0;
4681
4682 return rc;
4683}
4684
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004686CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004687 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004688 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689{
4690 int rc = 0;
4691 TRANSACTION2_QPI_REQ *pSMB = NULL;
4692 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4693 int name_len, bytes_returned;
4694 __u16 params, byte_count;
4695
Joe Perchesf96637b2013-05-04 22:12:25 -05004696 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004697 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004698 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699
4700GetInodeNumberRetry:
4701 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004702 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 if (rc)
4704 return rc;
4705
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4707 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004708 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004709 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004710 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 name_len++; /* trailing null */
4712 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004713 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004714 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004716 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 }
4718
4719 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4720 pSMB->TotalDataCount = 0;
4721 pSMB->MaxParameterCount = cpu_to_le16(2);
4722 /* BB find exact max data count below from sess structure BB */
4723 pSMB->MaxDataCount = cpu_to_le16(4000);
4724 pSMB->MaxSetupCount = 0;
4725 pSMB->Reserved = 0;
4726 pSMB->Flags = 0;
4727 pSMB->Timeout = 0;
4728 pSMB->Reserved2 = 0;
4729 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004730 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 pSMB->DataCount = 0;
4732 pSMB->DataOffset = 0;
4733 pSMB->SetupCount = 1;
4734 pSMB->Reserved3 = 0;
4735 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4736 byte_count = params + 1 /* pad */ ;
4737 pSMB->TotalParameterCount = cpu_to_le16(params);
4738 pSMB->ParameterCount = pSMB->TotalParameterCount;
4739 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4740 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004741 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 pSMB->ByteCount = cpu_to_le16(byte_count);
4743
4744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4746 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004747 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 } else {
4749 /* decode response */
4750 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004752 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 /* If rc should we check for EOPNOSUPP and
4754 disable the srvino flag? or in caller? */
4755 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004756 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4758 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004759 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004761 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004762 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 rc = -EIO;
4764 goto GetInodeNumOut;
4765 }
4766 pfinfo = (struct file_internal_info *)
4767 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004768 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 }
4770 }
4771GetInodeNumOut:
4772 cifs_buf_release(pSMB);
4773 if (rc == -EAGAIN)
4774 goto GetInodeNumberRetry;
4775 return rc;
4776}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777
Igor Mammedovfec45852008-05-16 13:06:30 +04004778/* parses DFS refferal V3 structure
4779 * caller is responsible for freeing target_nodes
4780 * returns:
4781 * on success - 0
4782 * on failure - errno
4783 */
4784static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004785parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004786 unsigned int *num_of_nodes,
4787 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004788 const struct nls_table *nls_codepage, int remap,
4789 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004790{
4791 int i, rc = 0;
4792 char *data_end;
4793 bool is_unicode;
4794 struct dfs_referral_level_3 *ref;
4795
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004796 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4797 is_unicode = true;
4798 else
4799 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004800 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4801
4802 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004803 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4804 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004805 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004806 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004807 }
4808
4809 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004810 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004811 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4812 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004813 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004814 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004815 }
4816
4817 /* get the upper boundary of the resp buffer */
4818 data_end = (char *)(&(pSMBr->PathConsumed)) +
4819 le16_to_cpu(pSMBr->t2.DataCount);
4820
Joe Perchesf96637b2013-05-04 22:12:25 -05004821 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4822 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004823
Joe Perchesf96637b2013-05-04 22:12:25 -05004824 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4825 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004826 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004827 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004828 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004829 }
4830
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004831 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004832 for (i = 0; i < *num_of_nodes; i++) {
4833 char *temp;
4834 int max_len;
4835 struct dfs_info3_param *node = (*target_nodes)+i;
4836
Steve French0e0d2cf2009-05-01 05:27:32 +00004837 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004838 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004839 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4840 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004841 if (tmp == NULL) {
4842 rc = -ENOMEM;
4843 goto parse_DFS_referrals_exit;
4844 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004845 cifsConvertToUTF16((__le16 *) tmp, searchName,
4846 PATH_MAX, nls_codepage, remap);
4847 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004848 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004849 nls_codepage);
4850 kfree(tmp);
4851 } else
4852 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4853
Igor Mammedovfec45852008-05-16 13:06:30 +04004854 node->server_type = le16_to_cpu(ref->ServerType);
4855 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4856
4857 /* copy DfsPath */
4858 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4859 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004860 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4861 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004862 if (!node->path_name) {
4863 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004864 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004865 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004866
4867 /* copy link target UNC */
4868 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4869 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004870 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4871 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004872 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004873 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004874 goto parse_DFS_referrals_exit;
4875 }
4876
4877 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004878 }
4879
Steve Frencha1fe78f2008-05-16 18:48:38 +00004880parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004881 if (rc) {
4882 free_dfs_info_array(*target_nodes, *num_of_nodes);
4883 *target_nodes = NULL;
4884 *num_of_nodes = 0;
4885 }
4886 return rc;
4887}
4888
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004890CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004891 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004892 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004893 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894{
4895/* TRANS2_GET_DFS_REFERRAL */
4896 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4897 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 int rc = 0;
4899 int bytes_returned;
4900 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004902 *num_of_nodes = 0;
4903 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904
Joe Perchesf96637b2013-05-04 22:12:25 -05004905 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 if (ses == NULL)
4907 return -ENODEV;
4908getDFSRetry:
4909 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4910 (void **) &pSMBr);
4911 if (rc)
4912 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004913
4914 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004915 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004916 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 pSMB->hdr.Tid = ses->ipc_tid;
4918 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004919 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004921 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923
4924 if (ses->capabilities & CAP_UNICODE) {
4925 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4926 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004927 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004928 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004929 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 name_len++; /* trailing null */
4931 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004932 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004933 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004935 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 }
4937
Dan Carpenter65c3b202015-04-30 17:30:24 +03004938 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004939 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004940
Steve French50c2f752007-07-13 00:33:32 +00004941 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004942
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 params = 2 /* level */ + name_len /*includes null */ ;
4944 pSMB->TotalDataCount = 0;
4945 pSMB->DataCount = 0;
4946 pSMB->DataOffset = 0;
4947 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004948 /* BB find exact max SMB PDU from sess structure BB */
4949 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 pSMB->MaxSetupCount = 0;
4951 pSMB->Reserved = 0;
4952 pSMB->Flags = 0;
4953 pSMB->Timeout = 0;
4954 pSMB->Reserved2 = 0;
4955 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004956 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 pSMB->SetupCount = 1;
4958 pSMB->Reserved3 = 0;
4959 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4960 byte_count = params + 3 /* pad */ ;
4961 pSMB->ParameterCount = cpu_to_le16(params);
4962 pSMB->TotalParameterCount = pSMB->ParameterCount;
4963 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004964 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 pSMB->ByteCount = cpu_to_le16(byte_count);
4966
4967 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4969 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004970 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004971 goto GetDFSRefExit;
4972 }
4973 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004975 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004976 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004977 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004978 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004980
Joe Perchesf96637b2013-05-04 22:12:25 -05004981 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4982 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004983
4984 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004985 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004986 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004987 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004988
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004990 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991
4992 if (rc == -EAGAIN)
4993 goto getDFSRetry;
4994
4995 return rc;
4996}
4997
Steve French20962432005-09-21 22:05:57 -07004998/* Query File System Info such as free space to old servers such as Win 9x */
4999int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005000SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5001 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005002{
5003/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5004 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5005 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5006 FILE_SYSTEM_ALLOC_INFO *response_data;
5007 int rc = 0;
5008 int bytes_returned = 0;
5009 __u16 params, byte_count;
5010
Joe Perchesf96637b2013-05-04 22:12:25 -05005011 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005012oldQFSInfoRetry:
5013 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5014 (void **) &pSMBr);
5015 if (rc)
5016 return rc;
Steve French20962432005-09-21 22:05:57 -07005017
5018 params = 2; /* level */
5019 pSMB->TotalDataCount = 0;
5020 pSMB->MaxParameterCount = cpu_to_le16(2);
5021 pSMB->MaxDataCount = cpu_to_le16(1000);
5022 pSMB->MaxSetupCount = 0;
5023 pSMB->Reserved = 0;
5024 pSMB->Flags = 0;
5025 pSMB->Timeout = 0;
5026 pSMB->Reserved2 = 0;
5027 byte_count = params + 1 /* pad */ ;
5028 pSMB->TotalParameterCount = cpu_to_le16(params);
5029 pSMB->ParameterCount = pSMB->TotalParameterCount;
5030 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5031 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5032 pSMB->DataCount = 0;
5033 pSMB->DataOffset = 0;
5034 pSMB->SetupCount = 1;
5035 pSMB->Reserved3 = 0;
5036 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5037 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005038 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005039 pSMB->ByteCount = cpu_to_le16(byte_count);
5040
5041 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5042 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5043 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005044 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005045 } else { /* decode response */
5046 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5047
Jeff Layton820a8032011-05-04 08:05:26 -04005048 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005049 rc = -EIO; /* bad smb */
5050 else {
5051 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005052 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005053 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005054
Steve French50c2f752007-07-13 00:33:32 +00005055 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005056 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5057 FSData->f_bsize =
5058 le16_to_cpu(response_data->BytesPerSector) *
5059 le32_to_cpu(response_data->
5060 SectorsPerAllocationUnit);
5061 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005062 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005063 FSData->f_bfree = FSData->f_bavail =
5064 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005065 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5066 (unsigned long long)FSData->f_blocks,
5067 (unsigned long long)FSData->f_bfree,
5068 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005069 }
5070 }
5071 cifs_buf_release(pSMB);
5072
5073 if (rc == -EAGAIN)
5074 goto oldQFSInfoRetry;
5075
5076 return rc;
5077}
5078
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005080CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5081 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082{
5083/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5084 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5085 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5086 FILE_SYSTEM_INFO *response_data;
5087 int rc = 0;
5088 int bytes_returned = 0;
5089 __u16 params, byte_count;
5090
Joe Perchesf96637b2013-05-04 22:12:25 -05005091 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092QFSInfoRetry:
5093 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5094 (void **) &pSMBr);
5095 if (rc)
5096 return rc;
5097
5098 params = 2; /* level */
5099 pSMB->TotalDataCount = 0;
5100 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005101 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 pSMB->MaxSetupCount = 0;
5103 pSMB->Reserved = 0;
5104 pSMB->Flags = 0;
5105 pSMB->Timeout = 0;
5106 pSMB->Reserved2 = 0;
5107 byte_count = params + 1 /* pad */ ;
5108 pSMB->TotalParameterCount = cpu_to_le16(params);
5109 pSMB->ParameterCount = pSMB->TotalParameterCount;
5110 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005111 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 pSMB->DataCount = 0;
5113 pSMB->DataOffset = 0;
5114 pSMB->SetupCount = 1;
5115 pSMB->Reserved3 = 0;
5116 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5117 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005118 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 pSMB->ByteCount = cpu_to_le16(byte_count);
5120
5121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5123 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005124 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005126 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127
Jeff Layton820a8032011-05-04 08:05:26 -04005128 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 rc = -EIO; /* bad smb */
5130 else {
5131 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132
5133 response_data =
5134 (FILE_SYSTEM_INFO
5135 *) (((char *) &pSMBr->hdr.Protocol) +
5136 data_offset);
5137 FSData->f_bsize =
5138 le32_to_cpu(response_data->BytesPerSector) *
5139 le32_to_cpu(response_data->
5140 SectorsPerAllocationUnit);
5141 FSData->f_blocks =
5142 le64_to_cpu(response_data->TotalAllocationUnits);
5143 FSData->f_bfree = FSData->f_bavail =
5144 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005145 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5146 (unsigned long long)FSData->f_blocks,
5147 (unsigned long long)FSData->f_bfree,
5148 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 }
5150 }
5151 cifs_buf_release(pSMB);
5152
5153 if (rc == -EAGAIN)
5154 goto QFSInfoRetry;
5155
5156 return rc;
5157}
5158
5159int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005160CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161{
5162/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5163 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5164 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5165 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5166 int rc = 0;
5167 int bytes_returned = 0;
5168 __u16 params, byte_count;
5169
Joe Perchesf96637b2013-05-04 22:12:25 -05005170 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171QFSAttributeRetry:
5172 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5173 (void **) &pSMBr);
5174 if (rc)
5175 return rc;
5176
5177 params = 2; /* level */
5178 pSMB->TotalDataCount = 0;
5179 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005180 /* BB find exact max SMB PDU from sess structure BB */
5181 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 pSMB->MaxSetupCount = 0;
5183 pSMB->Reserved = 0;
5184 pSMB->Flags = 0;
5185 pSMB->Timeout = 0;
5186 pSMB->Reserved2 = 0;
5187 byte_count = params + 1 /* pad */ ;
5188 pSMB->TotalParameterCount = cpu_to_le16(params);
5189 pSMB->ParameterCount = pSMB->TotalParameterCount;
5190 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005191 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 pSMB->DataCount = 0;
5193 pSMB->DataOffset = 0;
5194 pSMB->SetupCount = 1;
5195 pSMB->Reserved3 = 0;
5196 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5197 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005198 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 pSMB->ByteCount = cpu_to_le16(byte_count);
5200
5201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5203 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005204 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 } else { /* decode response */
5206 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5207
Jeff Layton820a8032011-05-04 08:05:26 -04005208 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005209 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 rc = -EIO; /* bad smb */
5211 } else {
5212 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5213 response_data =
5214 (FILE_SYSTEM_ATTRIBUTE_INFO
5215 *) (((char *) &pSMBr->hdr.Protocol) +
5216 data_offset);
5217 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005218 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 }
5220 }
5221 cifs_buf_release(pSMB);
5222
5223 if (rc == -EAGAIN)
5224 goto QFSAttributeRetry;
5225
5226 return rc;
5227}
5228
5229int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005230CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231{
5232/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5233 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5234 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5235 FILE_SYSTEM_DEVICE_INFO *response_data;
5236 int rc = 0;
5237 int bytes_returned = 0;
5238 __u16 params, byte_count;
5239
Joe Perchesf96637b2013-05-04 22:12:25 -05005240 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241QFSDeviceRetry:
5242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5243 (void **) &pSMBr);
5244 if (rc)
5245 return rc;
5246
5247 params = 2; /* level */
5248 pSMB->TotalDataCount = 0;
5249 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005250 /* BB find exact max SMB PDU from sess structure BB */
5251 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 pSMB->MaxSetupCount = 0;
5253 pSMB->Reserved = 0;
5254 pSMB->Flags = 0;
5255 pSMB->Timeout = 0;
5256 pSMB->Reserved2 = 0;
5257 byte_count = params + 1 /* pad */ ;
5258 pSMB->TotalParameterCount = cpu_to_le16(params);
5259 pSMB->ParameterCount = pSMB->TotalParameterCount;
5260 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005261 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262
5263 pSMB->DataCount = 0;
5264 pSMB->DataOffset = 0;
5265 pSMB->SetupCount = 1;
5266 pSMB->Reserved3 = 0;
5267 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5268 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005269 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 pSMB->ByteCount = cpu_to_le16(byte_count);
5271
5272 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5273 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5274 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005275 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 } else { /* decode response */
5277 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5278
Jeff Layton820a8032011-05-04 08:05:26 -04005279 if (rc || get_bcc(&pSMBr->hdr) <
5280 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 rc = -EIO; /* bad smb */
5282 else {
5283 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5284 response_data =
Steve French737b7582005-04-28 22:41:06 -07005285 (FILE_SYSTEM_DEVICE_INFO *)
5286 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 data_offset);
5288 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005289 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 }
5291 }
5292 cifs_buf_release(pSMB);
5293
5294 if (rc == -EAGAIN)
5295 goto QFSDeviceRetry;
5296
5297 return rc;
5298}
5299
5300int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005301CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302{
5303/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5304 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5305 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5306 FILE_SYSTEM_UNIX_INFO *response_data;
5307 int rc = 0;
5308 int bytes_returned = 0;
5309 __u16 params, byte_count;
5310
Joe Perchesf96637b2013-05-04 22:12:25 -05005311 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005313 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5314 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 if (rc)
5316 return rc;
5317
5318 params = 2; /* level */
5319 pSMB->TotalDataCount = 0;
5320 pSMB->DataCount = 0;
5321 pSMB->DataOffset = 0;
5322 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005323 /* BB find exact max SMB PDU from sess structure BB */
5324 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 pSMB->MaxSetupCount = 0;
5326 pSMB->Reserved = 0;
5327 pSMB->Flags = 0;
5328 pSMB->Timeout = 0;
5329 pSMB->Reserved2 = 0;
5330 byte_count = params + 1 /* pad */ ;
5331 pSMB->ParameterCount = cpu_to_le16(params);
5332 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005333 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5334 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 pSMB->SetupCount = 1;
5336 pSMB->Reserved3 = 0;
5337 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5338 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005339 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 pSMB->ByteCount = cpu_to_le16(byte_count);
5341
5342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5344 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005345 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 } else { /* decode response */
5347 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5348
Jeff Layton820a8032011-05-04 08:05:26 -04005349 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 rc = -EIO; /* bad smb */
5351 } else {
5352 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5353 response_data =
5354 (FILE_SYSTEM_UNIX_INFO
5355 *) (((char *) &pSMBr->hdr.Protocol) +
5356 data_offset);
5357 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005358 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 }
5360 }
5361 cifs_buf_release(pSMB);
5362
5363 if (rc == -EAGAIN)
5364 goto QFSUnixRetry;
5365
5366
5367 return rc;
5368}
5369
Jeremy Allisonac670552005-06-22 17:26:35 -07005370int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005371CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005372{
5373/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5374 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5375 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5376 int rc = 0;
5377 int bytes_returned = 0;
5378 __u16 params, param_offset, offset, byte_count;
5379
Joe Perchesf96637b2013-05-04 22:12:25 -05005380 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005381SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005382 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005383 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5384 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005385 if (rc)
5386 return rc;
5387
5388 params = 4; /* 2 bytes zero followed by info level. */
5389 pSMB->MaxSetupCount = 0;
5390 pSMB->Reserved = 0;
5391 pSMB->Flags = 0;
5392 pSMB->Timeout = 0;
5393 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005394 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5395 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005396 offset = param_offset + params;
5397
5398 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005399 /* BB find exact max SMB PDU from sess structure BB */
5400 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005401 pSMB->SetupCount = 1;
5402 pSMB->Reserved3 = 0;
5403 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5404 byte_count = 1 /* pad */ + params + 12;
5405
5406 pSMB->DataCount = cpu_to_le16(12);
5407 pSMB->ParameterCount = cpu_to_le16(params);
5408 pSMB->TotalDataCount = pSMB->DataCount;
5409 pSMB->TotalParameterCount = pSMB->ParameterCount;
5410 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5411 pSMB->DataOffset = cpu_to_le16(offset);
5412
5413 /* Params. */
5414 pSMB->FileNum = 0;
5415 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5416
5417 /* Data. */
5418 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5419 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5420 pSMB->ClientUnixCap = cpu_to_le64(cap);
5421
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005422 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005423 pSMB->ByteCount = cpu_to_le16(byte_count);
5424
5425 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5427 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005428 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005429 } else { /* decode response */
5430 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005431 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005432 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005433 }
5434 cifs_buf_release(pSMB);
5435
5436 if (rc == -EAGAIN)
5437 goto SETFSUnixRetry;
5438
5439 return rc;
5440}
5441
5442
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443
5444int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005445CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005446 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447{
5448/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5449 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5450 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5451 FILE_SYSTEM_POSIX_INFO *response_data;
5452 int rc = 0;
5453 int bytes_returned = 0;
5454 __u16 params, byte_count;
5455
Joe Perchesf96637b2013-05-04 22:12:25 -05005456 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457QFSPosixRetry:
5458 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5459 (void **) &pSMBr);
5460 if (rc)
5461 return rc;
5462
5463 params = 2; /* level */
5464 pSMB->TotalDataCount = 0;
5465 pSMB->DataCount = 0;
5466 pSMB->DataOffset = 0;
5467 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005468 /* BB find exact max SMB PDU from sess structure BB */
5469 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 pSMB->MaxSetupCount = 0;
5471 pSMB->Reserved = 0;
5472 pSMB->Flags = 0;
5473 pSMB->Timeout = 0;
5474 pSMB->Reserved2 = 0;
5475 byte_count = params + 1 /* pad */ ;
5476 pSMB->ParameterCount = cpu_to_le16(params);
5477 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005478 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5479 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 pSMB->SetupCount = 1;
5481 pSMB->Reserved3 = 0;
5482 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5483 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005484 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 pSMB->ByteCount = cpu_to_le16(byte_count);
5486
5487 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5488 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5489 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005490 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 } else { /* decode response */
5492 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5493
Jeff Layton820a8032011-05-04 08:05:26 -04005494 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 rc = -EIO; /* bad smb */
5496 } else {
5497 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5498 response_data =
5499 (FILE_SYSTEM_POSIX_INFO
5500 *) (((char *) &pSMBr->hdr.Protocol) +
5501 data_offset);
5502 FSData->f_bsize =
5503 le32_to_cpu(response_data->BlockSize);
5504 FSData->f_blocks =
5505 le64_to_cpu(response_data->TotalBlocks);
5506 FSData->f_bfree =
5507 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005508 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 FSData->f_bavail = FSData->f_bfree;
5510 } else {
5511 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005512 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 }
Steve French790fe572007-07-07 19:25:05 +00005514 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005516 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005517 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005519 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 }
5521 }
5522 cifs_buf_release(pSMB);
5523
5524 if (rc == -EAGAIN)
5525 goto QFSPosixRetry;
5526
5527 return rc;
5528}
5529
5530
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005531/*
5532 * We can not use write of zero bytes trick to set file size due to need for
5533 * large file support. Also note that this SetPathInfo is preferred to
5534 * SetFileInfo based method in next routine which is only needed to work around
5535 * a sharing violation bugin Samba which this routine can run into.
5536 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005538CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005539 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5540 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541{
5542 struct smb_com_transaction2_spi_req *pSMB = NULL;
5543 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5544 struct file_end_of_file_info *parm_data;
5545 int name_len;
5546 int rc = 0;
5547 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005548 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005549
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 __u16 params, byte_count, data_count, param_offset, offset;
5551
Joe Perchesf96637b2013-05-04 22:12:25 -05005552 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553SetEOFRetry:
5554 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5555 (void **) &pSMBr);
5556 if (rc)
5557 return rc;
5558
5559 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5560 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005561 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5562 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 name_len++; /* trailing null */
5564 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005565 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005566 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005568 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 }
5570 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005571 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005573 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 pSMB->MaxSetupCount = 0;
5575 pSMB->Reserved = 0;
5576 pSMB->Flags = 0;
5577 pSMB->Timeout = 0;
5578 pSMB->Reserved2 = 0;
5579 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005580 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005582 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005583 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5584 pSMB->InformationLevel =
5585 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5586 else
5587 pSMB->InformationLevel =
5588 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5589 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5591 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005592 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 else
5594 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005595 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 }
5597
5598 parm_data =
5599 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5600 offset);
5601 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5602 pSMB->DataOffset = cpu_to_le16(offset);
5603 pSMB->SetupCount = 1;
5604 pSMB->Reserved3 = 0;
5605 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5606 byte_count = 3 /* pad */ + params + data_count;
5607 pSMB->DataCount = cpu_to_le16(data_count);
5608 pSMB->TotalDataCount = pSMB->DataCount;
5609 pSMB->ParameterCount = cpu_to_le16(params);
5610 pSMB->TotalParameterCount = pSMB->ParameterCount;
5611 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005612 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 parm_data->FileSize = cpu_to_le64(size);
5614 pSMB->ByteCount = cpu_to_le16(byte_count);
5615 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5616 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005617 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005618 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619
5620 cifs_buf_release(pSMB);
5621
5622 if (rc == -EAGAIN)
5623 goto SetEOFRetry;
5624
5625 return rc;
5626}
5627
5628int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005629CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5630 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631{
5632 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 struct file_end_of_file_info *parm_data;
5634 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 __u16 params, param_offset, offset, byte_count, count;
5636
Joe Perchesf96637b2013-05-04 22:12:25 -05005637 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5638 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005639 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5640
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 if (rc)
5642 return rc;
5643
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005644 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5645 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005646
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 params = 6;
5648 pSMB->MaxSetupCount = 0;
5649 pSMB->Reserved = 0;
5650 pSMB->Flags = 0;
5651 pSMB->Timeout = 0;
5652 pSMB->Reserved2 = 0;
5653 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5654 offset = param_offset + params;
5655
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 count = sizeof(struct file_end_of_file_info);
5657 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005658 /* BB find exact max SMB PDU from sess structure BB */
5659 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 pSMB->SetupCount = 1;
5661 pSMB->Reserved3 = 0;
5662 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5663 byte_count = 3 /* pad */ + params + count;
5664 pSMB->DataCount = cpu_to_le16(count);
5665 pSMB->ParameterCount = cpu_to_le16(params);
5666 pSMB->TotalDataCount = pSMB->DataCount;
5667 pSMB->TotalParameterCount = pSMB->ParameterCount;
5668 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5669 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005670 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5671 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 pSMB->DataOffset = cpu_to_le16(offset);
5673 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005674 pSMB->Fid = cfile->fid.netfid;
5675 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5677 pSMB->InformationLevel =
5678 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5679 else
5680 pSMB->InformationLevel =
5681 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005682 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5684 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005685 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 else
5687 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005688 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 }
5690 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005691 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005693 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005695 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5696 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697 }
5698
Steve French50c2f752007-07-13 00:33:32 +00005699 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 since file handle passed in no longer valid */
5701
5702 return rc;
5703}
5704
Steve French50c2f752007-07-13 00:33:32 +00005705/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 an open handle, rather than by pathname - this is awkward due to
5707 potential access conflicts on the open, but it is unavoidable for these
5708 old servers since the only other choice is to go from 100 nanosecond DCE
5709 time and resort to the original setpathinfo level which takes the ancient
5710 DOS time format with 2 second granularity */
5711int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005712CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005713 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714{
5715 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 char *data_offset;
5717 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 __u16 params, param_offset, offset, byte_count, count;
5719
Joe Perchesf96637b2013-05-04 22:12:25 -05005720 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005721 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5722
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 if (rc)
5724 return rc;
5725
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005726 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5727 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005728
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 params = 6;
5730 pSMB->MaxSetupCount = 0;
5731 pSMB->Reserved = 0;
5732 pSMB->Flags = 0;
5733 pSMB->Timeout = 0;
5734 pSMB->Reserved2 = 0;
5735 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5736 offset = param_offset + params;
5737
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005738 data_offset = (char *)pSMB +
5739 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740
Steve French26f57362007-08-30 22:09:15 +00005741 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005743 /* BB find max SMB PDU from sess */
5744 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 pSMB->SetupCount = 1;
5746 pSMB->Reserved3 = 0;
5747 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5748 byte_count = 3 /* pad */ + params + count;
5749 pSMB->DataCount = cpu_to_le16(count);
5750 pSMB->ParameterCount = cpu_to_le16(params);
5751 pSMB->TotalDataCount = pSMB->DataCount;
5752 pSMB->TotalParameterCount = pSMB->ParameterCount;
5753 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5754 pSMB->DataOffset = cpu_to_le16(offset);
5755 pSMB->Fid = fid;
5756 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5757 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5758 else
5759 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5760 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005761 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005763 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005764 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005765 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005766 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5767 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
Steve French50c2f752007-07-13 00:33:32 +00005769 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 since file handle passed in no longer valid */
5771
5772 return rc;
5773}
5774
Jeff Layton6d22f092008-09-23 11:48:35 -04005775int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005776CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005777 bool delete_file, __u16 fid, __u32 pid_of_opener)
5778{
5779 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5780 char *data_offset;
5781 int rc = 0;
5782 __u16 params, param_offset, offset, byte_count, count;
5783
Joe Perchesf96637b2013-05-04 22:12:25 -05005784 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005785 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5786
5787 if (rc)
5788 return rc;
5789
5790 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5791 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5792
5793 params = 6;
5794 pSMB->MaxSetupCount = 0;
5795 pSMB->Reserved = 0;
5796 pSMB->Flags = 0;
5797 pSMB->Timeout = 0;
5798 pSMB->Reserved2 = 0;
5799 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5800 offset = param_offset + params;
5801
5802 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5803
5804 count = 1;
5805 pSMB->MaxParameterCount = cpu_to_le16(2);
5806 /* BB find max SMB PDU from sess */
5807 pSMB->MaxDataCount = cpu_to_le16(1000);
5808 pSMB->SetupCount = 1;
5809 pSMB->Reserved3 = 0;
5810 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5811 byte_count = 3 /* pad */ + params + count;
5812 pSMB->DataCount = cpu_to_le16(count);
5813 pSMB->ParameterCount = cpu_to_le16(params);
5814 pSMB->TotalDataCount = pSMB->DataCount;
5815 pSMB->TotalParameterCount = pSMB->ParameterCount;
5816 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5817 pSMB->DataOffset = cpu_to_le16(offset);
5818 pSMB->Fid = fid;
5819 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5820 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005821 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005822 pSMB->ByteCount = cpu_to_le16(byte_count);
5823 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005824 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005825 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005826 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005827
5828 return rc;
5829}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830
5831int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005832CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005833 const char *fileName, const FILE_BASIC_INFO *data,
5834 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835{
5836 TRANSACTION2_SPI_REQ *pSMB = NULL;
5837 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5838 int name_len;
5839 int rc = 0;
5840 int bytes_returned = 0;
5841 char *data_offset;
5842 __u16 params, param_offset, offset, byte_count, count;
5843
Joe Perchesf96637b2013-05-04 22:12:25 -05005844 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845
5846SetTimesRetry:
5847 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5848 (void **) &pSMBr);
5849 if (rc)
5850 return rc;
5851
5852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5853 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005854 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5855 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856 name_len++; /* trailing null */
5857 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005858 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 name_len = strnlen(fileName, PATH_MAX);
5860 name_len++; /* trailing null */
5861 strncpy(pSMB->FileName, fileName, name_len);
5862 }
5863
5864 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005865 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005867 /* BB find max SMB PDU from sess structure BB */
5868 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869 pSMB->MaxSetupCount = 0;
5870 pSMB->Reserved = 0;
5871 pSMB->Flags = 0;
5872 pSMB->Timeout = 0;
5873 pSMB->Reserved2 = 0;
5874 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005875 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 offset = param_offset + params;
5877 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5878 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5879 pSMB->DataOffset = cpu_to_le16(offset);
5880 pSMB->SetupCount = 1;
5881 pSMB->Reserved3 = 0;
5882 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5883 byte_count = 3 /* pad */ + params + count;
5884
5885 pSMB->DataCount = cpu_to_le16(count);
5886 pSMB->ParameterCount = cpu_to_le16(params);
5887 pSMB->TotalDataCount = pSMB->DataCount;
5888 pSMB->TotalParameterCount = pSMB->ParameterCount;
5889 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5890 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5891 else
5892 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5893 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005894 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005895 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 pSMB->ByteCount = cpu_to_le16(byte_count);
5897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005899 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005900 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901
5902 cifs_buf_release(pSMB);
5903
5904 if (rc == -EAGAIN)
5905 goto SetTimesRetry;
5906
5907 return rc;
5908}
5909
5910/* Can not be used to set time stamps yet (due to old DOS time format) */
5911/* Can be used to set attributes */
5912#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5913 handling it anyway and NT4 was what we thought it would be needed for
5914 Do not delete it until we prove whether needed for Win9x though */
5915int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005916CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 __u16 dos_attrs, const struct nls_table *nls_codepage)
5918{
5919 SETATTR_REQ *pSMB = NULL;
5920 SETATTR_RSP *pSMBr = NULL;
5921 int rc = 0;
5922 int bytes_returned;
5923 int name_len;
5924
Joe Perchesf96637b2013-05-04 22:12:25 -05005925 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926
5927SetAttrLgcyRetry:
5928 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5929 (void **) &pSMBr);
5930 if (rc)
5931 return rc;
5932
5933 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5934 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005935 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5936 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937 name_len++; /* trailing null */
5938 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005939 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 name_len = strnlen(fileName, PATH_MAX);
5941 name_len++; /* trailing null */
5942 strncpy(pSMB->fileName, fileName, name_len);
5943 }
5944 pSMB->attr = cpu_to_le16(dos_attrs);
5945 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005946 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005950 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005951 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952
5953 cifs_buf_release(pSMB);
5954
5955 if (rc == -EAGAIN)
5956 goto SetAttrLgcyRetry;
5957
5958 return rc;
5959}
5960#endif /* temporarily unneeded SetAttr legacy function */
5961
Jeff Layton654cf142009-07-09 20:02:49 -04005962static void
5963cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5964 const struct cifs_unix_set_info_args *args)
5965{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005966 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005967 u64 mode = args->mode;
5968
Eric W. Biederman49418b22013-02-06 00:57:56 -08005969 if (uid_valid(args->uid))
5970 uid = from_kuid(&init_user_ns, args->uid);
5971 if (gid_valid(args->gid))
5972 gid = from_kgid(&init_user_ns, args->gid);
5973
Jeff Layton654cf142009-07-09 20:02:49 -04005974 /*
5975 * Samba server ignores set of file size to zero due to bugs in some
5976 * older clients, but we should be precise - we use SetFileSize to
5977 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005978 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005979 * zero instead of -1 here
5980 */
5981 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5982 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5983 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5984 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5985 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005986 data_offset->Uid = cpu_to_le64(uid);
5987 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005988 /* better to leave device as zero when it is */
5989 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5990 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5991 data_offset->Permissions = cpu_to_le64(mode);
5992
5993 if (S_ISREG(mode))
5994 data_offset->Type = cpu_to_le32(UNIX_FILE);
5995 else if (S_ISDIR(mode))
5996 data_offset->Type = cpu_to_le32(UNIX_DIR);
5997 else if (S_ISLNK(mode))
5998 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5999 else if (S_ISCHR(mode))
6000 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6001 else if (S_ISBLK(mode))
6002 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6003 else if (S_ISFIFO(mode))
6004 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6005 else if (S_ISSOCK(mode))
6006 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6007}
6008
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006010CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006011 const struct cifs_unix_set_info_args *args,
6012 u16 fid, u32 pid_of_opener)
6013{
6014 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006015 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006016 int rc = 0;
6017 u16 params, param_offset, offset, byte_count, count;
6018
Joe Perchesf96637b2013-05-04 22:12:25 -05006019 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006020 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6021
6022 if (rc)
6023 return rc;
6024
6025 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6026 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6027
6028 params = 6;
6029 pSMB->MaxSetupCount = 0;
6030 pSMB->Reserved = 0;
6031 pSMB->Flags = 0;
6032 pSMB->Timeout = 0;
6033 pSMB->Reserved2 = 0;
6034 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6035 offset = param_offset + params;
6036
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006037 data_offset = (char *)pSMB +
6038 offsetof(struct smb_hdr, Protocol) + offset;
6039
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006040 count = sizeof(FILE_UNIX_BASIC_INFO);
6041
6042 pSMB->MaxParameterCount = cpu_to_le16(2);
6043 /* BB find max SMB PDU from sess */
6044 pSMB->MaxDataCount = cpu_to_le16(1000);
6045 pSMB->SetupCount = 1;
6046 pSMB->Reserved3 = 0;
6047 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6048 byte_count = 3 /* pad */ + params + count;
6049 pSMB->DataCount = cpu_to_le16(count);
6050 pSMB->ParameterCount = cpu_to_le16(params);
6051 pSMB->TotalDataCount = pSMB->DataCount;
6052 pSMB->TotalParameterCount = pSMB->ParameterCount;
6053 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6054 pSMB->DataOffset = cpu_to_le16(offset);
6055 pSMB->Fid = fid;
6056 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6057 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006058 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006059 pSMB->ByteCount = cpu_to_le16(byte_count);
6060
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006061 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006062
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006063 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006064 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006065 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6066 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006067
6068 /* Note: On -EAGAIN error only caller can retry on handle based calls
6069 since file handle passed in no longer valid */
6070
6071 return rc;
6072}
6073
6074int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006075CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006076 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006077 const struct cifs_unix_set_info_args *args,
6078 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079{
6080 TRANSACTION2_SPI_REQ *pSMB = NULL;
6081 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6082 int name_len;
6083 int rc = 0;
6084 int bytes_returned = 0;
6085 FILE_UNIX_BASIC_INFO *data_offset;
6086 __u16 params, param_offset, offset, count, byte_count;
6087
Joe Perchesf96637b2013-05-04 22:12:25 -05006088 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089setPermsRetry:
6090 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6091 (void **) &pSMBr);
6092 if (rc)
6093 return rc;
6094
6095 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6096 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006097 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006098 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099 name_len++; /* trailing null */
6100 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006101 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006102 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006104 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 }
6106
6107 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006108 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006110 /* BB find max SMB PDU from sess structure BB */
6111 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 pSMB->MaxSetupCount = 0;
6113 pSMB->Reserved = 0;
6114 pSMB->Flags = 0;
6115 pSMB->Timeout = 0;
6116 pSMB->Reserved2 = 0;
6117 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006118 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 offset = param_offset + params;
6120 data_offset =
6121 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6122 offset);
6123 memset(data_offset, 0, count);
6124 pSMB->DataOffset = cpu_to_le16(offset);
6125 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6126 pSMB->SetupCount = 1;
6127 pSMB->Reserved3 = 0;
6128 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6129 byte_count = 3 /* pad */ + params + count;
6130 pSMB->ParameterCount = cpu_to_le16(params);
6131 pSMB->DataCount = cpu_to_le16(count);
6132 pSMB->TotalParameterCount = pSMB->ParameterCount;
6133 pSMB->TotalDataCount = pSMB->DataCount;
6134 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6135 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006136 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006137
Jeff Layton654cf142009-07-09 20:02:49 -04006138 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139
6140 pSMB->ByteCount = cpu_to_le16(byte_count);
6141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006143 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006144 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145
Steve French0d817bc2008-05-22 02:02:03 +00006146 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 if (rc == -EAGAIN)
6148 goto setPermsRetry;
6149 return rc;
6150}
6151
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006153/*
6154 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6155 * function used by listxattr and getxattr type calls. When ea_name is set,
6156 * it looks for that attribute name and stuffs that value into the EAData
6157 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6158 * buffer. In both cases, the return value is either the length of the
6159 * resulting data or a negative error code. If EAData is a NULL pointer then
6160 * the data isn't copied to it, but the length is returned.
6161 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006162ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006163CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006164 const unsigned char *searchName, const unsigned char *ea_name,
6165 char *EAData, size_t buf_size,
6166 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167{
6168 /* BB assumes one setup word */
6169 TRANSACTION2_QPI_REQ *pSMB = NULL;
6170 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6171 int rc = 0;
6172 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006173 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006174 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006175 struct fea *temp_fea;
6176 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006177 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006179 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180
Joe Perchesf96637b2013-05-04 22:12:25 -05006181 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182QAllEAsRetry:
6183 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6184 (void **) &pSMBr);
6185 if (rc)
6186 return rc;
6187
6188 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006189 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006190 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6191 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006192 list_len++; /* trailing null */
6193 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006195 list_len = strnlen(searchName, PATH_MAX);
6196 list_len++; /* trailing null */
6197 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198 }
6199
Jeff Layton6e462b92010-02-10 16:18:26 -05006200 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 pSMB->TotalDataCount = 0;
6202 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006203 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006204 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205 pSMB->MaxSetupCount = 0;
6206 pSMB->Reserved = 0;
6207 pSMB->Flags = 0;
6208 pSMB->Timeout = 0;
6209 pSMB->Reserved2 = 0;
6210 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006211 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 pSMB->DataCount = 0;
6213 pSMB->DataOffset = 0;
6214 pSMB->SetupCount = 1;
6215 pSMB->Reserved3 = 0;
6216 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6217 byte_count = params + 1 /* pad */ ;
6218 pSMB->TotalParameterCount = cpu_to_le16(params);
6219 pSMB->ParameterCount = pSMB->TotalParameterCount;
6220 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6221 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006222 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223 pSMB->ByteCount = cpu_to_le16(byte_count);
6224
6225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6227 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006228 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006229 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006231
6232
6233 /* BB also check enough total bytes returned */
6234 /* BB we need to improve the validity checking
6235 of these trans2 responses */
6236
6237 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006238 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006239 rc = -EIO; /* bad smb */
6240 goto QAllEAsOut;
6241 }
6242
6243 /* check that length of list is not more than bcc */
6244 /* check that each entry does not go beyond length
6245 of list */
6246 /* check that each element of each entry does not
6247 go beyond end of list */
6248 /* validate_trans2_offsets() */
6249 /* BB check if start of smb + data_offset > &bcc+ bcc */
6250
6251 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6252 ea_response_data = (struct fealist *)
6253 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6254
Jeff Layton6e462b92010-02-10 16:18:26 -05006255 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006256 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006257 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006258 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006259 /* didn't find the named attribute */
6260 if (ea_name)
6261 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006262 goto QAllEAsOut;
6263 }
6264
Jeff Layton0cd126b2010-02-10 16:18:26 -05006265 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006266 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006267 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006268 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006269 rc = -EIO;
6270 goto QAllEAsOut;
6271 }
6272
Jeff Laytonf0d38682010-02-10 16:18:26 -05006273 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006274 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006275 temp_fea = ea_response_data->list;
6276 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006277 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006278 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006279 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006280
Jeff Layton6e462b92010-02-10 16:18:26 -05006281 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006282 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006283 /* make sure we can read name_len and value_len */
6284 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006285 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006286 rc = -EIO;
6287 goto QAllEAsOut;
6288 }
6289
6290 name_len = temp_fea->name_len;
6291 value_len = le16_to_cpu(temp_fea->value_len);
6292 list_len -= name_len + 1 + value_len;
6293 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006294 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006295 rc = -EIO;
6296 goto QAllEAsOut;
6297 }
6298
Jeff Layton31c05192010-02-10 16:18:26 -05006299 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006300 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006301 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006302 temp_ptr += name_len + 1;
6303 rc = value_len;
6304 if (buf_size == 0)
6305 goto QAllEAsOut;
6306 if ((size_t)value_len > buf_size) {
6307 rc = -ERANGE;
6308 goto QAllEAsOut;
6309 }
6310 memcpy(EAData, temp_ptr, value_len);
6311 goto QAllEAsOut;
6312 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006313 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006314 /* account for prefix user. and trailing null */
6315 rc += (5 + 1 + name_len);
6316 if (rc < (int) buf_size) {
6317 memcpy(EAData, "user.", 5);
6318 EAData += 5;
6319 memcpy(EAData, temp_ptr, name_len);
6320 EAData += name_len;
6321 /* null terminate name */
6322 *EAData = 0;
6323 ++EAData;
6324 } else if (buf_size == 0) {
6325 /* skip copy - calc size only */
6326 } else {
6327 /* stop before overrun buffer */
6328 rc = -ERANGE;
6329 break;
6330 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006331 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006332 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006333 temp_fea = (struct fea *)temp_ptr;
6334 }
6335
Jeff Layton31c05192010-02-10 16:18:26 -05006336 /* didn't find the named attribute */
6337 if (ea_name)
6338 rc = -ENODATA;
6339
Jeff Laytonf0d38682010-02-10 16:18:26 -05006340QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006341 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 if (rc == -EAGAIN)
6343 goto QAllEAsRetry;
6344
6345 return (ssize_t)rc;
6346}
6347
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006349CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6350 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006351 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6352 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353{
6354 struct smb_com_transaction2_spi_req *pSMB = NULL;
6355 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6356 struct fealist *parm_data;
6357 int name_len;
6358 int rc = 0;
6359 int bytes_returned = 0;
6360 __u16 params, param_offset, byte_count, offset, count;
6361
Joe Perchesf96637b2013-05-04 22:12:25 -05006362 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363SetEARetry:
6364 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6365 (void **) &pSMBr);
6366 if (rc)
6367 return rc;
6368
6369 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6370 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006371 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6372 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 name_len++; /* trailing null */
6374 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006375 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376 name_len = strnlen(fileName, PATH_MAX);
6377 name_len++; /* trailing null */
6378 strncpy(pSMB->FileName, fileName, name_len);
6379 }
6380
6381 params = 6 + name_len;
6382
6383 /* done calculating parms using name_len of file name,
6384 now use name_len to calculate length of ea name
6385 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006386 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 name_len = 0;
6388 else
Steve French50c2f752007-07-13 00:33:32 +00006389 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006391 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006393 /* BB find max SMB PDU from sess */
6394 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395 pSMB->MaxSetupCount = 0;
6396 pSMB->Reserved = 0;
6397 pSMB->Flags = 0;
6398 pSMB->Timeout = 0;
6399 pSMB->Reserved2 = 0;
6400 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006401 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402 offset = param_offset + params;
6403 pSMB->InformationLevel =
6404 cpu_to_le16(SMB_SET_FILE_EA);
6405
6406 parm_data =
6407 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6408 offset);
6409 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6410 pSMB->DataOffset = cpu_to_le16(offset);
6411 pSMB->SetupCount = 1;
6412 pSMB->Reserved3 = 0;
6413 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6414 byte_count = 3 /* pad */ + params + count;
6415 pSMB->DataCount = cpu_to_le16(count);
6416 parm_data->list_len = cpu_to_le32(count);
6417 parm_data->list[0].EA_flags = 0;
6418 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006419 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006421 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006422 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006423 parm_data->list[0].name[name_len] = 0;
6424 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6425 /* caller ensures that ea_value_len is less than 64K but
6426 we need to ensure that it fits within the smb */
6427
Steve French50c2f752007-07-13 00:33:32 +00006428 /*BB add length check to see if it would fit in
6429 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006430 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6431 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006432 memcpy(parm_data->list[0].name+name_len+1,
6433 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434
6435 pSMB->TotalDataCount = pSMB->DataCount;
6436 pSMB->ParameterCount = cpu_to_le16(params);
6437 pSMB->TotalParameterCount = pSMB->ParameterCount;
6438 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006439 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 pSMB->ByteCount = cpu_to_le16(byte_count);
6441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006443 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006444 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445
6446 cifs_buf_release(pSMB);
6447
6448 if (rc == -EAGAIN)
6449 goto SetEARetry;
6450
6451 return rc;
6452}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453#endif
Steve French0eff0e22011-02-24 05:39:23 +00006454
6455#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6456/*
6457 * Years ago the kernel added a "dnotify" function for Samba server,
6458 * to allow network clients (such as Windows) to display updated
6459 * lists of files in directory listings automatically when
6460 * files are added by one user when another user has the
6461 * same directory open on their desktop. The Linux cifs kernel
6462 * client hooked into the kernel side of this interface for
6463 * the same reason, but ironically when the VFS moved from
6464 * "dnotify" to "inotify" it became harder to plug in Linux
6465 * network file system clients (the most obvious use case
6466 * for notify interfaces is when multiple users can update
6467 * the contents of the same directory - exactly what network
6468 * file systems can do) although the server (Samba) could
6469 * still use it. For the short term we leave the worker
6470 * function ifdeffed out (below) until inotify is fixed
6471 * in the VFS to make it easier to plug in network file
6472 * system clients. If inotify turns out to be permanently
6473 * incompatible for network fs clients, we could instead simply
6474 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6475 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006476int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006477 const int notify_subdirs, const __u16 netfid,
6478 __u32 filter, struct file *pfile, int multishot,
6479 const struct nls_table *nls_codepage)
6480{
6481 int rc = 0;
6482 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6483 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6484 struct dir_notify_req *dnotify_req;
6485 int bytes_returned;
6486
Joe Perchesf96637b2013-05-04 22:12:25 -05006487 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006488 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6489 (void **) &pSMBr);
6490 if (rc)
6491 return rc;
6492
6493 pSMB->TotalParameterCount = 0 ;
6494 pSMB->TotalDataCount = 0;
6495 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006496 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006497 pSMB->MaxSetupCount = 4;
6498 pSMB->Reserved = 0;
6499 pSMB->ParameterOffset = 0;
6500 pSMB->DataCount = 0;
6501 pSMB->DataOffset = 0;
6502 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6503 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6504 pSMB->ParameterCount = pSMB->TotalParameterCount;
6505 if (notify_subdirs)
6506 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6507 pSMB->Reserved2 = 0;
6508 pSMB->CompletionFilter = cpu_to_le32(filter);
6509 pSMB->Fid = netfid; /* file handle always le */
6510 pSMB->ByteCount = 0;
6511
6512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6513 (struct smb_hdr *)pSMBr, &bytes_returned,
6514 CIFS_ASYNC_OP);
6515 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006516 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006517 } else {
6518 /* Add file to outstanding requests */
6519 /* BB change to kmem cache alloc */
6520 dnotify_req = kmalloc(
6521 sizeof(struct dir_notify_req),
6522 GFP_KERNEL);
6523 if (dnotify_req) {
6524 dnotify_req->Pid = pSMB->hdr.Pid;
6525 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6526 dnotify_req->Mid = pSMB->hdr.Mid;
6527 dnotify_req->Tid = pSMB->hdr.Tid;
6528 dnotify_req->Uid = pSMB->hdr.Uid;
6529 dnotify_req->netfid = netfid;
6530 dnotify_req->pfile = pfile;
6531 dnotify_req->filter = filter;
6532 dnotify_req->multishot = multishot;
6533 spin_lock(&GlobalMid_Lock);
6534 list_add_tail(&dnotify_req->lhead,
6535 &GlobalDnotifyReqList);
6536 spin_unlock(&GlobalMid_Lock);
6537 } else
6538 rc = -ENOMEM;
6539 }
6540 cifs_buf_release(pSMB);
6541 return rc;
6542}
6543#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */