blob: 1781a03aed5ed5b18245356443c1c545befbcf33 [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 */
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_lock(&cifs_file_list_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 }
Jeff Layton44772882010-10-15 15:34:03 -0400107 spin_unlock(&cifs_file_list_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 Layton502858822013-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);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400628 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000629 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Laytone598d1d82013-05-26 07:00:59 -0400630 (pSMBr->EncryptionKeyLength == 0)) {
631 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500632 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400633 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000634 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400635 } else {
636 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000637 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400638 }
Steve French254e55e2006-06-04 05:53:15 +0000639
640signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400641 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400642 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000643neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700644 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000645
Joe Perchesf96637b2013-05-04 22:12:25 -0500646 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return rc;
648}
649
650int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400651CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
653 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Joe Perchesf96637b2013-05-04 22:12:25 -0500656 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500657
658 /* BB: do we need to check this? These should never be NULL. */
659 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
660 return -EIO;
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500663 * No need to return error on this operation if tid invalidated and
664 * closed on server already e.g. due to tcp session crashing. Also,
665 * the tcon is no longer on the list, so no need to take lock before
666 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 */
Steve French268875b2009-06-25 00:29:21 +0000668 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000669 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Steve French50c2f752007-07-13 00:33:32 +0000671 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700672 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500673 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 return rc;
Steve French133672e2007-11-13 22:41:37 +0000675
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400676 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500678 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Steve French50c2f752007-07-13 00:33:32 +0000680 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (rc == -EAGAIN)
683 rc = 0;
684
685 return rc;
686}
687
Jeff Layton766fdbb2011-01-11 07:24:21 -0500688/*
689 * This is a no-op for now. We're not really interested in the reply, but
690 * rather in the fact that the server sent one and that server->lstrp
691 * gets updated.
692 *
693 * FIXME: maybe we should consider checking that the reply matches request?
694 */
695static void
696cifs_echo_callback(struct mid_q_entry *mid)
697{
698 struct TCP_Server_Info *server = mid->callback_data;
699
700 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400701 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500702}
703
704int
705CIFSSMBEcho(struct TCP_Server_Info *server)
706{
707 ECHO_REQ *smb;
708 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400709 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700710 struct smb_rqst rqst = { .rq_iov = &iov,
711 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500712
Joe Perchesf96637b2013-05-04 22:12:25 -0500713 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500714
715 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
716 if (rc)
717 return rc;
718
719 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000720 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500721 smb->hdr.WordCount = 1;
722 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400723 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500724 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000725 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400726 iov.iov_base = smb;
727 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500728
Jeff Laytonfec344e2012-09-18 16:20:35 -0700729 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400730 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500731 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500732 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500733
734 cifs_small_buf_release(smb);
735
736 return rc;
737}
738
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400740CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 LOGOFF_ANDX_REQ *pSMB;
743 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Joe Perchesf96637b2013-05-04 22:12:25 -0500745 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500746
747 /*
748 * BB: do we need to check validity of ses and server? They should
749 * always be valid since we have an active reference. If not, that
750 * should probably be a BUG()
751 */
752 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return -EIO;
754
Steve Frenchd7b619c2010-02-25 05:36:46 +0000755 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000756 if (ses->need_reconnect)
757 goto session_already_dead; /* no need to send SMBlogoff if uid
758 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
760 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000761 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return rc;
763 }
764
Pavel Shilovsky88257362012-05-23 14:01:59 +0400765 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700766
Jeff Layton38d77c52013-05-26 07:01:00 -0400767 if (ses->server->sign)
768 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 pSMB->hdr.Uid = ses->Suid;
771
772 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400773 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000774session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000775 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000778 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 error */
780 if (rc == -EAGAIN)
781 rc = 0;
782 return rc;
783}
784
785int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400786CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
787 const char *fileName, __u16 type,
788 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000789{
790 TRANSACTION2_SPI_REQ *pSMB = NULL;
791 TRANSACTION2_SPI_RSP *pSMBr = NULL;
792 struct unlink_psx_rq *pRqD;
793 int name_len;
794 int rc = 0;
795 int bytes_returned = 0;
796 __u16 params, param_offset, offset, byte_count;
797
Joe Perchesf96637b2013-05-04 22:12:25 -0500798 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000799PsxDelete:
800 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
801 (void **) &pSMBr);
802 if (rc)
803 return rc;
804
805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
806 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600807 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
808 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000809 name_len++; /* trailing null */
810 name_len *= 2;
811 } else { /* BB add path length overrun check */
812 name_len = strnlen(fileName, PATH_MAX);
813 name_len++; /* trailing null */
814 strncpy(pSMB->FileName, fileName, name_len);
815 }
816
817 params = 6 + name_len;
818 pSMB->MaxParameterCount = cpu_to_le16(2);
819 pSMB->MaxDataCount = 0; /* BB double check this with jra */
820 pSMB->MaxSetupCount = 0;
821 pSMB->Reserved = 0;
822 pSMB->Flags = 0;
823 pSMB->Timeout = 0;
824 pSMB->Reserved2 = 0;
825 param_offset = offsetof(struct smb_com_transaction2_spi_req,
826 InformationLevel) - 4;
827 offset = param_offset + params;
828
829 /* Setup pointer to Request Data (inode type) */
830 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
831 pRqD->type = cpu_to_le16(type);
832 pSMB->ParameterOffset = cpu_to_le16(param_offset);
833 pSMB->DataOffset = cpu_to_le16(offset);
834 pSMB->SetupCount = 1;
835 pSMB->Reserved3 = 0;
836 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
837 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
838
839 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
840 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
841 pSMB->ParameterCount = cpu_to_le16(params);
842 pSMB->TotalParameterCount = pSMB->ParameterCount;
843 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
844 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000845 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000846 pSMB->ByteCount = cpu_to_le16(byte_count);
847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000849 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500850 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000851 cifs_buf_release(pSMB);
852
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400853 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000854
855 if (rc == -EAGAIN)
856 goto PsxDelete;
857
858 return rc;
859}
860
861int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700862CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
863 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
865 DELETE_FILE_REQ *pSMB = NULL;
866 DELETE_FILE_RSP *pSMBr = NULL;
867 int rc = 0;
868 int bytes_returned;
869 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700870 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
872DelFileRetry:
873 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
874 (void **) &pSMBr);
875 if (rc)
876 return rc;
877
878 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700879 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
880 PATH_MAX, cifs_sb->local_nls,
881 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 name_len++; /* trailing null */
883 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700884 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700885 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700887 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 }
889 pSMB->SearchAttributes =
890 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
891 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000892 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 pSMB->ByteCount = cpu_to_le16(name_len + 1);
894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400896 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000897 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500898 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 cifs_buf_release(pSMB);
901 if (rc == -EAGAIN)
902 goto DelFileRetry;
903
904 return rc;
905}
906
907int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400908CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
909 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
911 DELETE_DIRECTORY_REQ *pSMB = NULL;
912 DELETE_DIRECTORY_RSP *pSMBr = NULL;
913 int rc = 0;
914 int bytes_returned;
915 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400916 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Joe Perchesf96637b2013-05-04 22:12:25 -0500918 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919RmDirRetry:
920 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
921 (void **) &pSMBr);
922 if (rc)
923 return rc;
924
925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400926 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
927 PATH_MAX, cifs_sb->local_nls,
928 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 name_len++; /* trailing null */
930 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700931 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400932 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400934 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 }
936
937 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000938 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 pSMB->ByteCount = cpu_to_le16(name_len + 1);
940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400942 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000943 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500944 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 cifs_buf_release(pSMB);
947 if (rc == -EAGAIN)
948 goto RmDirRetry;
949 return rc;
950}
951
952int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300953CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
954 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 int rc = 0;
957 CREATE_DIRECTORY_REQ *pSMB = NULL;
958 CREATE_DIRECTORY_RSP *pSMBr = NULL;
959 int bytes_returned;
960 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300961 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Joe Perchesf96637b2013-05-04 22:12:25 -0500963 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964MkDirRetry:
965 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
966 (void **) &pSMBr);
967 if (rc)
968 return rc;
969
970 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600971 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300972 PATH_MAX, cifs_sb->local_nls,
973 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 name_len++; /* trailing null */
975 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700976 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 name_len = strnlen(name, PATH_MAX);
978 name_len++; /* trailing null */
979 strncpy(pSMB->DirName, name, name_len);
980 }
981
982 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000983 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 pSMB->ByteCount = cpu_to_le16(name_len + 1);
985 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
986 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400987 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000988 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500989 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 cifs_buf_release(pSMB);
992 if (rc == -EAGAIN)
993 goto MkDirRetry;
994 return rc;
995}
996
Steve French2dd29d32007-04-23 22:07:35 +0000997int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400998CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
999 __u32 posix_flags, __u64 mode, __u16 *netfid,
1000 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1001 const char *name, const struct nls_table *nls_codepage,
1002 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001003{
1004 TRANSACTION2_SPI_REQ *pSMB = NULL;
1005 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1006 int name_len;
1007 int rc = 0;
1008 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001009 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001010 OPEN_PSX_REQ *pdata;
1011 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001012
Joe Perchesf96637b2013-05-04 22:12:25 -05001013 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001014PsxCreat:
1015 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1016 (void **) &pSMBr);
1017 if (rc)
1018 return rc;
1019
1020 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1021 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001022 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1023 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001024 name_len++; /* trailing null */
1025 name_len *= 2;
1026 } else { /* BB improve the check for buffer overruns BB */
1027 name_len = strnlen(name, PATH_MAX);
1028 name_len++; /* trailing null */
1029 strncpy(pSMB->FileName, name, name_len);
1030 }
1031
1032 params = 6 + name_len;
1033 count = sizeof(OPEN_PSX_REQ);
1034 pSMB->MaxParameterCount = cpu_to_le16(2);
1035 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1036 pSMB->MaxSetupCount = 0;
1037 pSMB->Reserved = 0;
1038 pSMB->Flags = 0;
1039 pSMB->Timeout = 0;
1040 pSMB->Reserved2 = 0;
1041 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001042 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001043 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001044 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001045 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001046 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001047 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001048 pdata->OpenFlags = cpu_to_le32(*pOplock);
1049 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1050 pSMB->DataOffset = cpu_to_le16(offset);
1051 pSMB->SetupCount = 1;
1052 pSMB->Reserved3 = 0;
1053 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1054 byte_count = 3 /* pad */ + params + count;
1055
1056 pSMB->DataCount = cpu_to_le16(count);
1057 pSMB->ParameterCount = cpu_to_le16(params);
1058 pSMB->TotalDataCount = pSMB->DataCount;
1059 pSMB->TotalParameterCount = pSMB->ParameterCount;
1060 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1061 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001062 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001063 pSMB->ByteCount = cpu_to_le16(byte_count);
1064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1066 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001067 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001068 goto psx_create_err;
1069 }
1070
Joe Perchesf96637b2013-05-04 22:12:25 -05001071 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001072 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1073
Jeff Layton820a8032011-05-04 08:05:26 -04001074 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001075 rc = -EIO; /* bad smb */
1076 goto psx_create_err;
1077 }
1078
1079 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001080 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001081 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001082
Steve French2dd29d32007-04-23 22:07:35 +00001083 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001084 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001085 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1086 /* Let caller know file was created so we can set the mode. */
1087 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001088 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001089 *pOplock |= CIFS_CREATE_ACTION;
1090 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001091 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1092 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001093 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001094 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001095 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001096 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001097 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001098 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001099 goto psx_create_err;
1100 }
Steve French50c2f752007-07-13 00:33:32 +00001101 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001102 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001103 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001104 }
Steve French2dd29d32007-04-23 22:07:35 +00001105
1106psx_create_err:
1107 cifs_buf_release(pSMB);
1108
Steve French65bc98b2009-07-10 15:27:25 +00001109 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001110 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001111 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001112 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001113
1114 if (rc == -EAGAIN)
1115 goto PsxCreat;
1116
Steve French50c2f752007-07-13 00:33:32 +00001117 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001118}
1119
Steve Frencha9d02ad2005-08-24 23:06:05 -07001120static __u16 convert_disposition(int disposition)
1121{
1122 __u16 ofun = 0;
1123
1124 switch (disposition) {
1125 case FILE_SUPERSEDE:
1126 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1127 break;
1128 case FILE_OPEN:
1129 ofun = SMBOPEN_OAPPEND;
1130 break;
1131 case FILE_CREATE:
1132 ofun = SMBOPEN_OCREATE;
1133 break;
1134 case FILE_OPEN_IF:
1135 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1136 break;
1137 case FILE_OVERWRITE:
1138 ofun = SMBOPEN_OTRUNC;
1139 break;
1140 case FILE_OVERWRITE_IF:
1141 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1142 break;
1143 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001144 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001145 ofun = SMBOPEN_OAPPEND; /* regular open */
1146 }
1147 return ofun;
1148}
1149
Jeff Layton35fc37d2008-05-14 10:22:03 -07001150static int
1151access_flags_to_smbopen_mode(const int access_flags)
1152{
1153 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1154
1155 if (masked_flags == GENERIC_READ)
1156 return SMBOPEN_READ;
1157 else if (masked_flags == GENERIC_WRITE)
1158 return SMBOPEN_WRITE;
1159
1160 /* just go for read/write */
1161 return SMBOPEN_READWRITE;
1162}
1163
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001165SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001166 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001167 const int access_flags, const int create_options, __u16 *netfid,
1168 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169 const struct nls_table *nls_codepage, int remap)
1170{
1171 int rc = -EACCES;
1172 OPENX_REQ *pSMB = NULL;
1173 OPENX_RSP *pSMBr = NULL;
1174 int bytes_returned;
1175 int name_len;
1176 __u16 count;
1177
1178OldOpenRetry:
1179 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1180 (void **) &pSMBr);
1181 if (rc)
1182 return rc;
1183
1184 pSMB->AndXCommand = 0xFF; /* none */
1185
1186 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1187 count = 1; /* account for one byte pad to word boundary */
1188 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001189 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1190 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001191 name_len++; /* trailing null */
1192 name_len *= 2;
1193 } else { /* BB improve check for buffer overruns BB */
1194 count = 0; /* no pad */
1195 name_len = strnlen(fileName, PATH_MAX);
1196 name_len++; /* trailing null */
1197 strncpy(pSMB->fileName, fileName, name_len);
1198 }
1199 if (*pOplock & REQ_OPLOCK)
1200 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001201 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001202 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001203
Steve Frencha9d02ad2005-08-24 23:06:05 -07001204 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001205 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1207 /* set file as system file if special file such
1208 as fifo and server expecting SFU style and
1209 no Unix extensions */
1210
Steve French790fe572007-07-07 19:25:05 +00001211 if (create_options & CREATE_OPTION_SPECIAL)
1212 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001213 else /* BB FIXME BB */
1214 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215
Jeff Layton67750fb2008-05-09 22:28:02 +00001216 if (create_options & CREATE_OPTION_READONLY)
1217 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001218
1219 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001220/* pSMB->CreateOptions = cpu_to_le32(create_options &
1221 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001223
1224 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001225 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001227 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228
1229 pSMB->ByteCount = cpu_to_le16(count);
1230 /* long_op set to 1 to allow for oplock break timeouts */
1231 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;
1283 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
1284 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
1398cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1399{
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;
1402 struct cifs_readdata *rdata = mid->callback_data;
1403
1404 while (remaining > 0) {
1405 int length;
1406
1407 length = cifs_read_from_socket(server, server->bigbuf,
1408 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001409 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001410 if (length < 0)
1411 return length;
1412 server->total_read += length;
1413 remaining -= length;
1414 }
1415
1416 dequeue_mid(mid, rdata->result);
1417 return 0;
1418}
1419
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001420int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001421cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1422{
1423 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001424 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001426 char *buf = server->smallbuf;
1427 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001428
Joe Perchesf96637b2013-05-04 22:12:25 -05001429 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1430 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001431
1432 /*
1433 * read the rest of READ_RSP header (sans Data array), or whatever we
1434 * can if there's not enough data. At this point, we've read down to
1435 * the Mid.
1436 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001437 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001438 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001439
Jeff Layton58195752012-09-19 06:22:34 -07001440 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1441 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001442
Jeff Layton58195752012-09-19 06:22:34 -07001443 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001444 if (length < 0)
1445 return length;
1446 server->total_read += length;
1447
1448 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001449 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001451 cifs_dbg(FYI, "%s: server returned error %d\n",
1452 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453 return cifs_readv_discard(server, mid);
1454 }
1455
1456 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001457 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001458 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1459 __func__, server->total_read,
1460 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001461 rdata->result = -EIO;
1462 return cifs_readv_discard(server, mid);
1463 }
1464
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001465 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001466 if (data_offset < server->total_read) {
1467 /*
1468 * win2k8 sometimes sends an offset of 0 when the read
1469 * is beyond the EOF. Treat it as if the data starts just after
1470 * the header.
1471 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001472 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1473 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001474 data_offset = server->total_read;
1475 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1476 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001477 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1478 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479 rdata->result = -EIO;
1480 return cifs_readv_discard(server, mid);
1481 }
1482
Joe Perchesf96637b2013-05-04 22:12:25 -05001483 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1484 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001485
1486 len = data_offset - server->total_read;
1487 if (len > 0) {
1488 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001489 rdata->iov.iov_base = buf + server->total_read;
1490 rdata->iov.iov_len = len;
1491 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001492 if (length < 0)
1493 return length;
1494 server->total_read += length;
1495 }
1496
1497 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001498 rdata->iov.iov_base = buf;
1499 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001500 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1501 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001502
1503 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001504 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001505 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506 /* data_len is corrupt -- discard frame */
1507 rdata->result = -EIO;
1508 return cifs_readv_discard(server, mid);
1509 }
1510
Jeff Layton8321fec2012-09-19 06:22:32 -07001511 length = rdata->read_into_pages(server, rdata, data_len);
1512 if (length < 0)
1513 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514
Jeff Layton8321fec2012-09-19 06:22:32 -07001515 server->total_read += length;
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001516 rdata->got_bytes = length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001517
Joe Perchesf96637b2013-05-04 22:12:25 -05001518 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1519 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520
1521 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001522 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001523 return cifs_readv_discard(server, mid);
1524
1525 dequeue_mid(mid, false);
1526 return length;
1527}
1528
1529static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001530cifs_readv_callback(struct mid_q_entry *mid)
1531{
1532 struct cifs_readdata *rdata = mid->callback_data;
1533 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1534 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001535 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1536 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001537 .rq_pages = rdata->pages,
1538 .rq_npages = rdata->nr_pages,
1539 .rq_pagesz = rdata->pagesz,
1540 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541
Joe Perchesf96637b2013-05-04 22:12:25 -05001542 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1543 __func__, mid->mid, mid->mid_state, rdata->result,
1544 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001546 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547 case MID_RESPONSE_RECEIVED:
1548 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001549 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001550 int rc = 0;
1551
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001552 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001553 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001554 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001555 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1556 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557 }
1558 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001559 task_io_account_read(rdata->got_bytes);
1560 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001561 break;
1562 case MID_REQUEST_SUBMITTED:
1563 case MID_RETRY_NEEDED:
1564 rdata->result = -EAGAIN;
1565 break;
1566 default:
1567 rdata->result = -EIO;
1568 }
1569
Jeff Laytonda472fc2012-03-23 14:40:53 -04001570 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001571 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001572 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573}
1574
1575/* cifs_async_readv - send an async write, and set up mid to handle result */
1576int
1577cifs_async_readv(struct cifs_readdata *rdata)
1578{
1579 int rc;
1580 READ_REQ *smb = NULL;
1581 int wct;
1582 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001583 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001584 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585
Joe Perchesf96637b2013-05-04 22:12:25 -05001586 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1587 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001588
1589 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1590 wct = 12;
1591 else {
1592 wct = 10; /* old style read */
1593 if ((rdata->offset >> 32) > 0) {
1594 /* can not handle this big offset for old */
1595 return -EIO;
1596 }
1597 }
1598
1599 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1600 if (rc)
1601 return rc;
1602
1603 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1604 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1605
1606 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001607 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1609 if (wct == 12)
1610 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1611 smb->Remaining = 0;
1612 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1613 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1614 if (wct == 12)
1615 smb->ByteCount = 0;
1616 else {
1617 /* old style read */
1618 struct smb_com_readx_req *smbr =
1619 (struct smb_com_readx_req *)smb;
1620 smbr->ByteCount = 0;
1621 }
1622
1623 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001624 rdata->iov.iov_base = smb;
1625 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001626
Jeff Layton6993f742012-05-16 07:13:17 -04001627 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001628 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1629 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630
1631 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001632 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001633 else
1634 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001635
1636 cifs_small_buf_release(smb);
1637 return rc;
1638}
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001641CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1642 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643{
1644 int rc = -EACCES;
1645 READ_REQ *pSMB = NULL;
1646 READ_RSP *pSMBr = NULL;
1647 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001648 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001649 int resp_buf_type = 0;
1650 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001651 __u32 pid = io_parms->pid;
1652 __u16 netfid = io_parms->netfid;
1653 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001654 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001655 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
Joe Perchesf96637b2013-05-04 22:12:25 -05001657 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001658 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001659 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001660 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001661 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001662 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001663 /* can not handle this big offset for old */
1664 return -EIO;
1665 }
1666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001669 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (rc)
1671 return rc;
1672
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001673 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1674 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 /* tcon and ses pointer are checked in smb_init */
1677 if (tcon->ses->server == NULL)
1678 return -ECONNABORTED;
1679
Steve Frenchec637e32005-12-12 20:53:18 -08001680 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001682 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001683 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001684 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 pSMB->Remaining = 0;
1687 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1688 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001689 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001690 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1691 else {
1692 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001693 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001694 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001695 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001696 }
Steve Frenchec637e32005-12-12 20:53:18 -08001697
1698 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001699 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001700 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001701 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001702 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001703 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001705 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 } else {
1707 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1708 data_length = data_length << 16;
1709 data_length += le16_to_cpu(pSMBr->DataLength);
1710 *nbytes = data_length;
1711
1712 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001713 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001715 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001716 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 rc = -EIO;
1718 *nbytes = 0;
1719 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001720 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001721 le16_to_cpu(pSMBr->DataOffset);
1722/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001723 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001724 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001725 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001726 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001727 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 }
1729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Steve French4b8f9302006-02-26 16:41:18 +00001731/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001732 if (*buf) {
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01001733 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001734 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001735 /* return buffer to caller to free */
1736 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001737 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001738 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001739 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001740 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001741 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001742
1743 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 since file handle passed in no longer valid */
1745 return rc;
1746}
1747
Steve Frenchec637e32005-12-12 20:53:18 -08001748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001750CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001751 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001752 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753{
1754 int rc = -EACCES;
1755 WRITE_REQ *pSMB = NULL;
1756 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001757 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 __u32 bytes_sent;
1759 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001760 __u32 pid = io_parms->pid;
1761 __u16 netfid = io_parms->netfid;
1762 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001763 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001764 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
Steve Frencha24e2d72010-04-03 17:20:21 +00001766 *nbytes = 0;
1767
Joe Perchesf96637b2013-05-04 22:12:25 -05001768 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001769 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001770 return -ECONNABORTED;
1771
Steve French790fe572007-07-07 19:25:05 +00001772 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001773 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001774 else {
Steve French1c955182005-08-30 20:58:07 -07001775 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001776 if ((offset >> 32) > 0) {
1777 /* can not handle big offset for old srv */
1778 return -EIO;
1779 }
1780 }
Steve French1c955182005-08-30 20:58:07 -07001781
1782 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 (void **) &pSMBr);
1784 if (rc)
1785 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001786
1787 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1788 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 /* tcon and ses pointer are checked in smb_init */
1791 if (tcon->ses->server == NULL)
1792 return -ECONNABORTED;
1793
1794 pSMB->AndXCommand = 0xFF; /* none */
1795 pSMB->Fid = netfid;
1796 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001797 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001798 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001799
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 pSMB->Reserved = 0xFFFFFFFF;
1801 pSMB->WriteMode = 0;
1802 pSMB->Remaining = 0;
1803
Steve French50c2f752007-07-13 00:33:32 +00001804 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 can send more if LARGE_WRITE_X capability returned by the server and if
1806 our buffer is big enough or if we convert to iovecs on socket writes
1807 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001808 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1810 } else {
1811 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1812 & ~0xFF;
1813 }
1814
1815 if (bytes_sent > count)
1816 bytes_sent = count;
1817 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001818 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001819 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001820 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001821 else if (ubuf) {
1822 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 cifs_buf_release(pSMB);
1824 return -EFAULT;
1825 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001826 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 /* No buffer */
1828 cifs_buf_release(pSMB);
1829 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001830 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001831 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001832 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001833 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001834 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1837 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001838 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001839
Steve French790fe572007-07-07 19:25:05 +00001840 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001841 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001842 else { /* old style write has byte count 4 bytes earlier
1843 so 4 bytes pad */
1844 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001845 (struct smb_com_writex_req *)pSMB;
1846 pSMBW->ByteCount = cpu_to_le16(byte_count);
1847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
1849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1850 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001851 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001853 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 } else {
1855 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1856 *nbytes = (*nbytes) << 16;
1857 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301858
1859 /*
1860 * Mask off high 16 bits when bytes written as returned by the
1861 * server is greater than bytes requested by the client. Some
1862 * OS/2 servers are known to set incorrect CountHigh values.
1863 */
1864 if (*nbytes > count)
1865 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 }
1867
1868 cifs_buf_release(pSMB);
1869
Steve French50c2f752007-07-13 00:33:32 +00001870 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 since file handle passed in no longer valid */
1872
1873 return rc;
1874}
1875
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001876void
1877cifs_writedata_release(struct kref *refcount)
1878{
1879 struct cifs_writedata *wdata = container_of(refcount,
1880 struct cifs_writedata, refcount);
1881
1882 if (wdata->cfile)
1883 cifsFileInfo_put(wdata->cfile);
1884
1885 kfree(wdata);
1886}
1887
1888/*
1889 * Write failed with a retryable error. Resend the write request. It's also
1890 * possible that the page was redirtied so re-clean the page.
1891 */
1892static void
1893cifs_writev_requeue(struct cifs_writedata *wdata)
1894{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001895 int i, rc = 0;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001896 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001897 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001898 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001899
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001900 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1901 i = 0;
1902 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001903 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001904 struct cifs_writedata *wdata2;
1905 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001906
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001907 wsize = server->ops->wp_retry_size(inode);
1908 if (wsize < rest_len) {
1909 nr_pages = wsize / PAGE_CACHE_SIZE;
1910 if (!nr_pages) {
1911 rc = -ENOTSUPP;
1912 break;
1913 }
1914 cur_len = nr_pages * PAGE_CACHE_SIZE;
1915 tailsz = PAGE_CACHE_SIZE;
1916 } else {
1917 nr_pages = DIV_ROUND_UP(rest_len, PAGE_CACHE_SIZE);
1918 cur_len = rest_len;
1919 tailsz = rest_len - (nr_pages - 1) * PAGE_CACHE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001920 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001921
1922 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1923 if (!wdata2) {
1924 rc = -ENOMEM;
1925 break;
1926 }
1927
1928 for (j = 0; j < nr_pages; j++) {
1929 wdata2->pages[j] = wdata->pages[i + j];
1930 lock_page(wdata2->pages[j]);
1931 clear_page_dirty_for_io(wdata2->pages[j]);
1932 }
1933
1934 wdata2->sync_mode = wdata->sync_mode;
1935 wdata2->nr_pages = nr_pages;
1936 wdata2->offset = page_offset(wdata2->pages[0]);
1937 wdata2->pagesz = PAGE_CACHE_SIZE;
1938 wdata2->tailsz = tailsz;
1939 wdata2->bytes = cur_len;
1940
1941 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
1942 if (!wdata2->cfile) {
1943 cifs_dbg(VFS, "No writable handles for inode\n");
1944 rc = -EBADF;
1945 break;
1946 }
1947 wdata2->pid = wdata2->cfile->pid;
1948 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
1949
1950 for (j = 0; j < nr_pages; j++) {
1951 unlock_page(wdata2->pages[j]);
1952 if (rc != 0 && rc != -EAGAIN) {
1953 SetPageError(wdata2->pages[j]);
1954 end_page_writeback(wdata2->pages[j]);
1955 page_cache_release(wdata2->pages[j]);
1956 }
1957 }
1958
1959 if (rc) {
1960 kref_put(&wdata2->refcount, cifs_writedata_release);
1961 if (rc == -EAGAIN)
1962 continue;
1963 break;
1964 }
1965
1966 rest_len -= cur_len;
1967 i += nr_pages;
1968 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001969
1970 mapping_set_error(inode->i_mapping, rc);
1971 kref_put(&wdata->refcount, cifs_writedata_release);
1972}
1973
Jeff Laytonc2e87642012-03-23 14:40:55 -04001974void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001975cifs_writev_complete(struct work_struct *work)
1976{
1977 struct cifs_writedata *wdata = container_of(work,
1978 struct cifs_writedata, work);
1979 struct inode *inode = wdata->cfile->dentry->d_inode;
1980 int i = 0;
1981
1982 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001983 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001984 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001985 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001986 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1987 wdata->bytes);
1988 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1989 return cifs_writev_requeue(wdata);
1990
1991 for (i = 0; i < wdata->nr_pages; i++) {
1992 struct page *page = wdata->pages[i];
1993 if (wdata->result == -EAGAIN)
1994 __set_page_dirty_nobuffers(page);
1995 else if (wdata->result < 0)
1996 SetPageError(page);
1997 end_page_writeback(page);
1998 page_cache_release(page);
1999 }
2000 if (wdata->result != -EAGAIN)
2001 mapping_set_error(inode->i_mapping, wdata->result);
2002 kref_put(&wdata->refcount, cifs_writedata_release);
2003}
2004
2005struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002006cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002007{
2008 struct cifs_writedata *wdata;
2009
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002010 /* writedata + number of page pointers */
2011 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002012 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002013 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002014 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002015 INIT_LIST_HEAD(&wdata->list);
2016 init_completion(&wdata->done);
2017 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002018 }
2019 return wdata;
2020}
2021
2022/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002023 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002024 * workqueue completion task.
2025 */
2026static void
2027cifs_writev_callback(struct mid_q_entry *mid)
2028{
2029 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002030 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002031 unsigned int written;
2032 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2033
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002034 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002035 case MID_RESPONSE_RECEIVED:
2036 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2037 if (wdata->result != 0)
2038 break;
2039
2040 written = le16_to_cpu(smb->CountHigh);
2041 written <<= 16;
2042 written += le16_to_cpu(smb->Count);
2043 /*
2044 * Mask off high 16 bits when bytes written as returned
2045 * by the server is greater than bytes requested by the
2046 * client. OS/2 servers are known to set incorrect
2047 * CountHigh values.
2048 */
2049 if (written > wdata->bytes)
2050 written &= 0xFFFF;
2051
2052 if (written < wdata->bytes)
2053 wdata->result = -ENOSPC;
2054 else
2055 wdata->bytes = written;
2056 break;
2057 case MID_REQUEST_SUBMITTED:
2058 case MID_RETRY_NEEDED:
2059 wdata->result = -EAGAIN;
2060 break;
2061 default:
2062 wdata->result = -EIO;
2063 break;
2064 }
2065
Jeff Laytonda472fc2012-03-23 14:40:53 -04002066 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002067 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002068 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002069}
2070
2071/* cifs_async_writev - send an async write, and set up mid to handle result */
2072int
Steve French4a5c80d2014-02-07 20:45:12 -06002073cifs_async_writev(struct cifs_writedata *wdata,
2074 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002075{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002076 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077 WRITE_REQ *smb = NULL;
2078 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002079 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002080 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002081 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082
2083 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2084 wct = 14;
2085 } else {
2086 wct = 12;
2087 if (wdata->offset >> 32 > 0) {
2088 /* can not handle big offset for old srv */
2089 return -EIO;
2090 }
2091 }
2092
2093 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2094 if (rc)
2095 goto async_writev_out;
2096
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002097 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2098 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002099
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002100 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002101 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2103 if (wct == 14)
2104 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2105 smb->Reserved = 0xFFFFFFFF;
2106 smb->WriteMode = 0;
2107 smb->Remaining = 0;
2108
2109 smb->DataOffset =
2110 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2111
2112 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002113 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2114 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002115
Jeff Laytoneddb0792012-09-18 16:20:35 -07002116 rqst.rq_iov = &iov;
2117 rqst.rq_nvec = 1;
2118 rqst.rq_pages = wdata->pages;
2119 rqst.rq_npages = wdata->nr_pages;
2120 rqst.rq_pagesz = wdata->pagesz;
2121 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122
Joe Perchesf96637b2013-05-04 22:12:25 -05002123 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2124 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002125
2126 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2127 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2128
2129 if (wct == 14) {
2130 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2131 put_bcc(wdata->bytes + 1, &smb->hdr);
2132 } else {
2133 /* wct == 12 */
2134 struct smb_com_writex_req *smbw =
2135 (struct smb_com_writex_req *)smb;
2136 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2137 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002138 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002139 }
2140
2141 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002142 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2143 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002144
2145 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002146 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002147 else
Steve French4a5c80d2014-02-07 20:45:12 -06002148 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002149
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002150async_writev_out:
2151 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002152 return rc;
2153}
2154
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002155int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002156CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002157 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158{
2159 int rc = -EACCES;
2160 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002161 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002162 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002163 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002164 __u32 pid = io_parms->pid;
2165 __u16 netfid = io_parms->netfid;
2166 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002167 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002168 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002170 *nbytes = 0;
2171
Joe Perchesf96637b2013-05-04 22:12:25 -05002172 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002173
Steve French4c3130e2008-12-09 00:28:16 +00002174 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002175 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002176 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002177 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002178 if ((offset >> 32) > 0) {
2179 /* can not handle big offset for old srv */
2180 return -EIO;
2181 }
2182 }
Steve French8cc64c62005-10-03 13:49:43 -07002183 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 if (rc)
2185 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002186
2187 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2188 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2189
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 /* tcon and ses pointer are checked in smb_init */
2191 if (tcon->ses->server == NULL)
2192 return -ECONNABORTED;
2193
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002194 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 pSMB->Fid = netfid;
2196 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002197 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002198 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 pSMB->Reserved = 0xFFFFFFFF;
2200 pSMB->WriteMode = 0;
2201 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002202
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002204 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
Steve French3e844692005-10-03 13:37:24 -07002206 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2207 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002208 /* header + 1 byte pad */
2209 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002210 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002211 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002212 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002213 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002214 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002215 pSMB->ByteCount = cpu_to_le16(count + 1);
2216 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002217 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002218 (struct smb_com_writex_req *)pSMB;
2219 pSMBW->ByteCount = cpu_to_le16(count + 5);
2220 }
Steve French3e844692005-10-03 13:37:24 -07002221 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002222 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002223 iov[0].iov_len = smb_hdr_len + 4;
2224 else /* wct == 12 pad bigger by four bytes */
2225 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002226
Steve French3e844692005-10-03 13:37:24 -07002227
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002228 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002229 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002231 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002232 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002233 /* presumably this can not happen, but best to be safe */
2234 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002235 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002236 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002237 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2238 *nbytes = (*nbytes) << 16;
2239 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302240
2241 /*
2242 * Mask off high 16 bits when bytes written as returned by the
2243 * server is greater than bytes requested by the client. OS/2
2244 * servers are known to set incorrect CountHigh values.
2245 */
2246 if (*nbytes > count)
2247 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
Steve French4b8f9302006-02-26 16:41:18 +00002250/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002251 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Steve French50c2f752007-07-13 00:33:32 +00002253 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 since file handle passed in no longer valid */
2255
2256 return rc;
2257}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002258
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002259int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2260 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002261 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2262{
2263 int rc = 0;
2264 LOCK_REQ *pSMB = NULL;
2265 struct kvec iov[2];
2266 int resp_buf_type;
2267 __u16 count;
2268
Joe Perchesf96637b2013-05-04 22:12:25 -05002269 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2270 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002271
2272 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2273 if (rc)
2274 return rc;
2275
2276 pSMB->Timeout = 0;
2277 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2278 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2279 pSMB->LockType = lock_type;
2280 pSMB->AndXCommand = 0xFF; /* none */
2281 pSMB->Fid = netfid; /* netfid stays le */
2282
2283 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2284 inc_rfc1001_len(pSMB, count);
2285 pSMB->ByteCount = cpu_to_le16(count);
2286
2287 iov[0].iov_base = (char *)pSMB;
2288 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2289 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2290 iov[1].iov_base = (char *)buf;
2291 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2292
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002293 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002294 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2295 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002296 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002297
2298 return rc;
2299}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002302CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002303 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002305 const __u32 numLock, const __u8 lockType,
2306 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307{
2308 int rc = 0;
2309 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002310/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002312 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 __u16 count;
2314
Joe Perchesf96637b2013-05-04 22:12:25 -05002315 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2316 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002317 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2318
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 if (rc)
2320 return rc;
2321
Steve French790fe572007-07-07 19:25:05 +00002322 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002323 /* no response expected */
2324 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002326 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002327 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2329 } else {
2330 pSMB->Timeout = 0;
2331 }
2332
2333 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2334 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2335 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002336 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 pSMB->AndXCommand = 0xFF; /* none */
2338 pSMB->Fid = smb_file_id; /* netfid stays le */
2339
Steve French790fe572007-07-07 19:25:05 +00002340 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002341 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 /* BB where to store pid high? */
2343 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2344 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2345 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2346 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2347 count = sizeof(LOCKING_ANDX_RANGE);
2348 } else {
2349 /* oplock break */
2350 count = 0;
2351 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002352 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 pSMB->ByteCount = cpu_to_le16(count);
2354
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002355 if (waitFlag) {
2356 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002357 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002358 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002359 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002360 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002361 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002362 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002363 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002364 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002365 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Steve French50c2f752007-07-13 00:33:32 +00002367 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 since file handle passed in no longer valid */
2369 return rc;
2370}
2371
2372int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002373CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002374 const __u16 smb_file_id, const __u32 netpid,
2375 const loff_t start_offset, const __u64 len,
2376 struct file_lock *pLockData, const __u16 lock_type,
2377 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002378{
2379 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2380 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002381 struct cifs_posix_lock *parm_data;
2382 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002383 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002384 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002385 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002386 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002387 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002388
Joe Perchesf96637b2013-05-04 22:12:25 -05002389 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002390
Steve French08547b02006-02-28 22:39:25 +00002391 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2392
2393 if (rc)
2394 return rc;
2395
2396 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2397
Steve French50c2f752007-07-13 00:33:32 +00002398 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002399 pSMB->MaxSetupCount = 0;
2400 pSMB->Reserved = 0;
2401 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002402 pSMB->Reserved2 = 0;
2403 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2404 offset = param_offset + params;
2405
Steve French08547b02006-02-28 22:39:25 +00002406 count = sizeof(struct cifs_posix_lock);
2407 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002408 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002409 pSMB->SetupCount = 1;
2410 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002411 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002412 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2413 else
2414 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2415 byte_count = 3 /* pad */ + params + count;
2416 pSMB->DataCount = cpu_to_le16(count);
2417 pSMB->ParameterCount = cpu_to_le16(params);
2418 pSMB->TotalDataCount = pSMB->DataCount;
2419 pSMB->TotalParameterCount = pSMB->ParameterCount;
2420 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002421 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002422 (((char *) &pSMB->hdr.Protocol) + offset);
2423
2424 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002425 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002426 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002427 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002428 pSMB->Timeout = cpu_to_le32(-1);
2429 } else
2430 pSMB->Timeout = 0;
2431
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002432 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002433 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002434 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002435
2436 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002437 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002438 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2439 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002440 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002441 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002442 if (waitFlag) {
2443 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2444 (struct smb_hdr *) pSMBr, &bytes_returned);
2445 } else {
Steve French133672e2007-11-13 22:41:37 +00002446 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002447 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002448 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2449 &resp_buf_type, timeout);
2450 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2451 not try to free it twice below on exit */
2452 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002453 }
2454
Steve French08547b02006-02-28 22:39:25 +00002455 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002456 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002457 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002458 /* lock structure can be returned on get */
2459 __u16 data_offset;
2460 __u16 data_count;
2461 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002462
Jeff Layton820a8032011-05-04 08:05:26 -04002463 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002464 rc = -EIO; /* bad smb */
2465 goto plk_err_exit;
2466 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002467 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2468 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002469 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002470 rc = -EIO;
2471 goto plk_err_exit;
2472 }
2473 parm_data = (struct cifs_posix_lock *)
2474 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002475 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002476 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002477 else {
2478 if (parm_data->lock_type ==
2479 __constant_cpu_to_le16(CIFS_RDLCK))
2480 pLockData->fl_type = F_RDLCK;
2481 else if (parm_data->lock_type ==
2482 __constant_cpu_to_le16(CIFS_WRLCK))
2483 pLockData->fl_type = F_WRLCK;
2484
Steve French5443d132011-03-13 05:08:25 +00002485 pLockData->fl_start = le64_to_cpu(parm_data->start);
2486 pLockData->fl_end = pLockData->fl_start +
2487 le64_to_cpu(parm_data->length) - 1;
2488 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002489 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002490 }
Steve French50c2f752007-07-13 00:33:32 +00002491
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002492plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002493 if (pSMB)
2494 cifs_small_buf_release(pSMB);
2495
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002496 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French133672e2007-11-13 22:41:37 +00002497
Steve French08547b02006-02-28 22:39:25 +00002498 /* Note: On -EAGAIN error only caller can retry on handle based calls
2499 since file handle passed in no longer valid */
2500
2501 return rc;
2502}
2503
2504
2505int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002506CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507{
2508 int rc = 0;
2509 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002510 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512/* do not retry on dead session on close */
2513 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002514 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 return 0;
2516 if (rc)
2517 return rc;
2518
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002520 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002522 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002523 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002525 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002527 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 }
2529 }
2530
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002532 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 rc = 0;
2534
2535 return rc;
2536}
2537
2538int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002539CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002540{
2541 int rc = 0;
2542 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002543 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002544
2545 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2546 if (rc)
2547 return rc;
2548
2549 pSMB->FileID = (__u16) smb_file_id;
2550 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002551 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002552 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002553 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002554 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002555
2556 return rc;
2557}
2558
2559int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002560CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002561 const char *from_name, const char *to_name,
2562 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563{
2564 int rc = 0;
2565 RENAME_REQ *pSMB = NULL;
2566 RENAME_RSP *pSMBr = NULL;
2567 int bytes_returned;
2568 int name_len, name_len2;
2569 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002570 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
Joe Perchesf96637b2013-05-04 22:12:25 -05002572 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573renameRetry:
2574 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2575 (void **) &pSMBr);
2576 if (rc)
2577 return rc;
2578
2579 pSMB->BufferFormat = 0x04;
2580 pSMB->SearchAttributes =
2581 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2582 ATTR_DIRECTORY);
2583
2584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002585 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2586 from_name, PATH_MAX,
2587 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 name_len++; /* trailing null */
2589 name_len *= 2;
2590 pSMB->OldFileName[name_len] = 0x04; /* pad */
2591 /* protocol requires ASCII signature byte on Unicode string */
2592 pSMB->OldFileName[name_len + 1] = 0x00;
2593 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002594 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002595 to_name, PATH_MAX, cifs_sb->local_nls,
2596 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2598 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002599 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002600 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002602 strncpy(pSMB->OldFileName, from_name, name_len);
2603 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 name_len2++; /* trailing null */
2605 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002606 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 name_len2++; /* trailing null */
2608 name_len2++; /* signature byte */
2609 }
2610
2611 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002612 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 pSMB->ByteCount = cpu_to_le16(count);
2614
2615 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2616 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002617 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002618 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002619 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 cifs_buf_release(pSMB);
2622
2623 if (rc == -EAGAIN)
2624 goto renameRetry;
2625
2626 return rc;
2627}
2628
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002629int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002630 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002631 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632{
2633 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2634 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002635 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 char *data_offset;
2637 char dummy_string[30];
2638 int rc = 0;
2639 int bytes_returned = 0;
2640 int len_of_str;
2641 __u16 params, param_offset, offset, count, byte_count;
2642
Joe Perchesf96637b2013-05-04 22:12:25 -05002643 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2645 (void **) &pSMBr);
2646 if (rc)
2647 return rc;
2648
2649 params = 6;
2650 pSMB->MaxSetupCount = 0;
2651 pSMB->Reserved = 0;
2652 pSMB->Flags = 0;
2653 pSMB->Timeout = 0;
2654 pSMB->Reserved2 = 0;
2655 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2656 offset = param_offset + params;
2657
2658 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2659 rename_info = (struct set_file_rename *) data_offset;
2660 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002661 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 pSMB->SetupCount = 1;
2663 pSMB->Reserved3 = 0;
2664 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2665 byte_count = 3 /* pad */ + params;
2666 pSMB->ParameterCount = cpu_to_le16(params);
2667 pSMB->TotalParameterCount = pSMB->ParameterCount;
2668 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2669 pSMB->DataOffset = cpu_to_le16(offset);
2670 /* construct random name ".cifs_tmp<inodenum><mid>" */
2671 rename_info->overwrite = cpu_to_le32(1);
2672 rename_info->root_fid = 0;
2673 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002674 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002675 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002676 len_of_str =
2677 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002678 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002680 len_of_str =
2681 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002682 target_name, PATH_MAX, nls_codepage,
2683 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 }
2685 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002686 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 byte_count += count;
2688 pSMB->DataCount = cpu_to_le16(count);
2689 pSMB->TotalDataCount = pSMB->DataCount;
2690 pSMB->Fid = netfid;
2691 pSMB->InformationLevel =
2692 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2693 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002694 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 pSMB->ByteCount = cpu_to_le16(byte_count);
2696 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002697 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002698 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002699 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002700 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2701 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002702
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 cifs_buf_release(pSMB);
2704
2705 /* Note: On -EAGAIN error only caller can retry on handle based calls
2706 since file handle passed in no longer valid */
2707
2708 return rc;
2709}
2710
2711int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002712CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2713 const char *fromName, const __u16 target_tid, const char *toName,
2714 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715{
2716 int rc = 0;
2717 COPY_REQ *pSMB = NULL;
2718 COPY_RSP *pSMBr = NULL;
2719 int bytes_returned;
2720 int name_len, name_len2;
2721 __u16 count;
2722
Joe Perchesf96637b2013-05-04 22:12:25 -05002723 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724copyRetry:
2725 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2726 (void **) &pSMBr);
2727 if (rc)
2728 return rc;
2729
2730 pSMB->BufferFormat = 0x04;
2731 pSMB->Tid2 = target_tid;
2732
2733 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2734
2735 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002736 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2737 fromName, PATH_MAX, nls_codepage,
2738 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 name_len++; /* trailing null */
2740 name_len *= 2;
2741 pSMB->OldFileName[name_len] = 0x04; /* pad */
2742 /* protocol requires ASCII signature byte on Unicode string */
2743 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002744 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002745 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2746 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2748 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002749 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 name_len = strnlen(fromName, PATH_MAX);
2751 name_len++; /* trailing null */
2752 strncpy(pSMB->OldFileName, fromName, name_len);
2753 name_len2 = strnlen(toName, PATH_MAX);
2754 name_len2++; /* trailing null */
2755 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2756 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2757 name_len2++; /* trailing null */
2758 name_len2++; /* signature byte */
2759 }
2760
2761 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002762 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 pSMB->ByteCount = cpu_to_le16(count);
2764
2765 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2766 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2767 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002768 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2769 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 }
Steve French0d817bc2008-05-22 02:02:03 +00002771 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
2773 if (rc == -EAGAIN)
2774 goto copyRetry;
2775
2776 return rc;
2777}
2778
2779int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002780CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 const char *fromName, const char *toName,
2782 const struct nls_table *nls_codepage)
2783{
2784 TRANSACTION2_SPI_REQ *pSMB = NULL;
2785 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2786 char *data_offset;
2787 int name_len;
2788 int name_len_target;
2789 int rc = 0;
2790 int bytes_returned = 0;
2791 __u16 params, param_offset, offset, byte_count;
2792
Joe Perchesf96637b2013-05-04 22:12:25 -05002793 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794createSymLinkRetry:
2795 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2796 (void **) &pSMBr);
2797 if (rc)
2798 return rc;
2799
2800 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2801 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002802 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2803 /* find define for this maxpathcomponent */
2804 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 name_len++; /* trailing null */
2806 name_len *= 2;
2807
Steve French50c2f752007-07-13 00:33:32 +00002808 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 name_len = strnlen(fromName, PATH_MAX);
2810 name_len++; /* trailing null */
2811 strncpy(pSMB->FileName, fromName, name_len);
2812 }
2813 params = 6 + name_len;
2814 pSMB->MaxSetupCount = 0;
2815 pSMB->Reserved = 0;
2816 pSMB->Flags = 0;
2817 pSMB->Timeout = 0;
2818 pSMB->Reserved2 = 0;
2819 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002820 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 offset = param_offset + params;
2822
2823 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2825 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002826 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2827 /* find define for this maxpathcomponent */
2828 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 name_len_target++; /* trailing null */
2830 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002831 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 name_len_target = strnlen(toName, PATH_MAX);
2833 name_len_target++; /* trailing null */
2834 strncpy(data_offset, toName, name_len_target);
2835 }
2836
2837 pSMB->MaxParameterCount = cpu_to_le16(2);
2838 /* BB find exact max on data count below from sess */
2839 pSMB->MaxDataCount = cpu_to_le16(1000);
2840 pSMB->SetupCount = 1;
2841 pSMB->Reserved3 = 0;
2842 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2843 byte_count = 3 /* pad */ + params + name_len_target;
2844 pSMB->DataCount = cpu_to_le16(name_len_target);
2845 pSMB->ParameterCount = cpu_to_le16(params);
2846 pSMB->TotalDataCount = pSMB->DataCount;
2847 pSMB->TotalParameterCount = pSMB->ParameterCount;
2848 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2849 pSMB->DataOffset = cpu_to_le16(offset);
2850 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2851 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002852 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 pSMB->ByteCount = cpu_to_le16(byte_count);
2854 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2855 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002856 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002857 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002858 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2859 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860
Steve French0d817bc2008-05-22 02:02:03 +00002861 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
2863 if (rc == -EAGAIN)
2864 goto createSymLinkRetry;
2865
2866 return rc;
2867}
2868
2869int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002870CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002872 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873{
2874 TRANSACTION2_SPI_REQ *pSMB = NULL;
2875 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2876 char *data_offset;
2877 int name_len;
2878 int name_len_target;
2879 int rc = 0;
2880 int bytes_returned = 0;
2881 __u16 params, param_offset, offset, byte_count;
2882
Joe Perchesf96637b2013-05-04 22:12:25 -05002883 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884createHardLinkRetry:
2885 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2886 (void **) &pSMBr);
2887 if (rc)
2888 return rc;
2889
2890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002891 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 name_len++; /* trailing null */
2894 name_len *= 2;
2895
Steve French50c2f752007-07-13 00:33:32 +00002896 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 name_len = strnlen(toName, PATH_MAX);
2898 name_len++; /* trailing null */
2899 strncpy(pSMB->FileName, toName, name_len);
2900 }
2901 params = 6 + name_len;
2902 pSMB->MaxSetupCount = 0;
2903 pSMB->Reserved = 0;
2904 pSMB->Flags = 0;
2905 pSMB->Timeout = 0;
2906 pSMB->Reserved2 = 0;
2907 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002908 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 offset = param_offset + params;
2910
2911 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2912 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2913 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002914 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2915 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 name_len_target++; /* trailing null */
2917 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002918 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 name_len_target = strnlen(fromName, PATH_MAX);
2920 name_len_target++; /* trailing null */
2921 strncpy(data_offset, fromName, name_len_target);
2922 }
2923
2924 pSMB->MaxParameterCount = cpu_to_le16(2);
2925 /* BB find exact max on data count below from sess*/
2926 pSMB->MaxDataCount = cpu_to_le16(1000);
2927 pSMB->SetupCount = 1;
2928 pSMB->Reserved3 = 0;
2929 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2930 byte_count = 3 /* pad */ + params + name_len_target;
2931 pSMB->ParameterCount = cpu_to_le16(params);
2932 pSMB->TotalParameterCount = pSMB->ParameterCount;
2933 pSMB->DataCount = cpu_to_le16(name_len_target);
2934 pSMB->TotalDataCount = pSMB->DataCount;
2935 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2936 pSMB->DataOffset = cpu_to_le16(offset);
2937 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2938 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002939 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 pSMB->ByteCount = cpu_to_le16(byte_count);
2941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002943 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002944 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002945 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2946 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
2948 cifs_buf_release(pSMB);
2949 if (rc == -EAGAIN)
2950 goto createHardLinkRetry;
2951
2952 return rc;
2953}
2954
2955int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002956CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002957 const char *from_name, const char *to_name,
2958 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959{
2960 int rc = 0;
2961 NT_RENAME_REQ *pSMB = NULL;
2962 RENAME_RSP *pSMBr = NULL;
2963 int bytes_returned;
2964 int name_len, name_len2;
2965 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002966 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
Joe Perchesf96637b2013-05-04 22:12:25 -05002968 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969winCreateHardLinkRetry:
2970
2971 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2972 (void **) &pSMBr);
2973 if (rc)
2974 return rc;
2975
2976 pSMB->SearchAttributes =
2977 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2978 ATTR_DIRECTORY);
2979 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2980 pSMB->ClusterCount = 0;
2981
2982 pSMB->BufferFormat = 0x04;
2983
2984 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2985 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002986 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2987 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 name_len++; /* trailing null */
2989 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002990
2991 /* protocol specifies ASCII buffer format (0x04) for unicode */
2992 pSMB->OldFileName[name_len] = 0x04;
2993 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002995 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002996 to_name, PATH_MAX, cifs_sb->local_nls,
2997 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2999 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003000 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003001 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003003 strncpy(pSMB->OldFileName, from_name, name_len);
3004 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 name_len2++; /* trailing null */
3006 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003007 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 name_len2++; /* trailing null */
3009 name_len2++; /* signature byte */
3010 }
3011
3012 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003013 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 pSMB->ByteCount = cpu_to_le16(count);
3015
3016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003018 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003019 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003020 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003021
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 cifs_buf_release(pSMB);
3023 if (rc == -EAGAIN)
3024 goto winCreateHardLinkRetry;
3025
3026 return rc;
3027}
3028
3029int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003030CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003031 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 const struct nls_table *nls_codepage)
3033{
3034/* SMB_QUERY_FILE_UNIX_LINK */
3035 TRANSACTION2_QPI_REQ *pSMB = NULL;
3036 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3037 int rc = 0;
3038 int bytes_returned;
3039 int name_len;
3040 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003041 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
Joe Perchesf96637b2013-05-04 22:12:25 -05003043 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
3045querySymLinkRetry:
3046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3047 (void **) &pSMBr);
3048 if (rc)
3049 return rc;
3050
3051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3052 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003053 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3054 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 name_len++; /* trailing null */
3056 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003057 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 name_len = strnlen(searchName, PATH_MAX);
3059 name_len++; /* trailing null */
3060 strncpy(pSMB->FileName, searchName, name_len);
3061 }
3062
3063 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3064 pSMB->TotalDataCount = 0;
3065 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003066 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 pSMB->MaxSetupCount = 0;
3068 pSMB->Reserved = 0;
3069 pSMB->Flags = 0;
3070 pSMB->Timeout = 0;
3071 pSMB->Reserved2 = 0;
3072 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003073 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 pSMB->DataCount = 0;
3075 pSMB->DataOffset = 0;
3076 pSMB->SetupCount = 1;
3077 pSMB->Reserved3 = 0;
3078 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3079 byte_count = params + 1 /* pad */ ;
3080 pSMB->TotalParameterCount = cpu_to_le16(params);
3081 pSMB->ParameterCount = pSMB->TotalParameterCount;
3082 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3083 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003084 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 pSMB->ByteCount = cpu_to_le16(byte_count);
3086
3087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3088 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3089 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003090 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 } else {
3092 /* decode response */
3093
3094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003096 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003097 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003099 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003100 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101
Jeff Layton460b9692009-04-30 07:17:56 -04003102 data_start = ((char *) &pSMBr->hdr.Protocol) +
3103 le16_to_cpu(pSMBr->t2.DataOffset);
3104
Steve French0e0d2cf2009-05-01 05:27:32 +00003105 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3106 is_unicode = true;
3107 else
3108 is_unicode = false;
3109
Steve French737b7582005-04-28 22:41:06 -07003110 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003111 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3112 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003113 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003114 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 }
3116 }
3117 cifs_buf_release(pSMB);
3118 if (rc == -EAGAIN)
3119 goto querySymLinkRetry;
3120 return rc;
3121}
3122
Steve Frenchc52a95542011-02-24 06:16:22 +00003123/*
3124 * Recent Windows versions now create symlinks more frequently
3125 * and they use the "reparse point" mechanism below. We can of course
3126 * do symlinks nicely to Samba and other servers which support the
3127 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3128 * "MF" symlinks optionally, but for recent Windows we really need to
3129 * reenable the code below and fix the cifs_symlink callers to handle this.
3130 * In the interim this code has been moved to its own config option so
3131 * it is not compiled in by default until callers fixed up and more tested.
3132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003134CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3135 __u16 fid, char **symlinkinfo,
3136 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137{
3138 int rc = 0;
3139 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003140 struct smb_com_transaction_ioctl_req *pSMB;
3141 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003142 bool is_unicode;
3143 unsigned int sub_len;
3144 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003145 struct reparse_symlink_data *reparse_buf;
3146 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003147 __u32 data_offset, data_count;
3148 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003150 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3152 (void **) &pSMBr);
3153 if (rc)
3154 return rc;
3155
3156 pSMB->TotalParameterCount = 0 ;
3157 pSMB->TotalDataCount = 0;
3158 pSMB->MaxParameterCount = cpu_to_le32(2);
3159 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003160 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 pSMB->MaxSetupCount = 4;
3162 pSMB->Reserved = 0;
3163 pSMB->ParameterOffset = 0;
3164 pSMB->DataCount = 0;
3165 pSMB->DataOffset = 0;
3166 pSMB->SetupCount = 4;
3167 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3168 pSMB->ParameterCount = pSMB->TotalParameterCount;
3169 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3170 pSMB->IsFsctl = 1; /* FSCTL */
3171 pSMB->IsRootFlag = 0;
3172 pSMB->Fid = fid; /* file handle always le */
3173 pSMB->ByteCount = 0;
3174
3175 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3176 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3177 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003178 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003179 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 }
Steve French989c7e52009-05-02 05:32:20 +00003181
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003182 data_offset = le32_to_cpu(pSMBr->DataOffset);
3183 data_count = le32_to_cpu(pSMBr->DataCount);
3184 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3185 /* BB also check enough total bytes returned */
3186 rc = -EIO; /* bad smb */
3187 goto qreparse_out;
3188 }
3189 if (!data_count || (data_count > 2048)) {
3190 rc = -EIO;
3191 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3192 goto qreparse_out;
3193 }
3194 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003195 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003196 ((char *)&pSMBr->hdr.Protocol + data_offset);
3197 if ((char *)reparse_buf >= end_of_smb) {
3198 rc = -EIO;
3199 goto qreparse_out;
3200 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003201 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3202 cifs_dbg(FYI, "NFS style reparse tag\n");
3203 posix_buf = (struct reparse_posix_data *)reparse_buf;
3204
3205 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3206 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3207 le64_to_cpu(posix_buf->InodeType));
3208 rc = -EOPNOTSUPP;
3209 goto qreparse_out;
3210 }
3211 is_unicode = true;
3212 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3213 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3214 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3215 rc = -EIO;
3216 goto qreparse_out;
3217 }
3218 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3219 sub_len, is_unicode, nls_codepage);
3220 goto qreparse_out;
3221 } else if (reparse_buf->ReparseTag !=
3222 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3223 rc = -EOPNOTSUPP;
3224 goto qreparse_out;
3225 }
3226
3227 /* Reparse tag is NTFS symlink */
3228 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3229 reparse_buf->PathBuffer;
3230 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3231 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003232 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3233 rc = -EIO;
3234 goto qreparse_out;
3235 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003236 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3237 is_unicode = true;
3238 else
3239 is_unicode = false;
3240
3241 /* BB FIXME investigate remapping reserved chars here */
3242 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3243 nls_codepage);
3244 if (!*symlinkinfo)
3245 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003247 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003249 /*
3250 * Note: On -EAGAIN error only caller can retry on handle based calls
3251 * since file handle passed in no longer valid.
3252 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 return rc;
3254}
3255
Steve Frenchc7f508a2013-10-14 15:27:32 -05003256int
3257CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3258 __u16 fid)
3259{
3260 int rc = 0;
3261 int bytes_returned;
3262 struct smb_com_transaction_compr_ioctl_req *pSMB;
3263 struct smb_com_transaction_ioctl_rsp *pSMBr;
3264
3265 cifs_dbg(FYI, "Set compression for %u\n", fid);
3266 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3267 (void **) &pSMBr);
3268 if (rc)
3269 return rc;
3270
3271 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3272
3273 pSMB->TotalParameterCount = 0;
3274 pSMB->TotalDataCount = __constant_cpu_to_le32(2);
3275 pSMB->MaxParameterCount = 0;
3276 pSMB->MaxDataCount = 0;
3277 pSMB->MaxSetupCount = 4;
3278 pSMB->Reserved = 0;
3279 pSMB->ParameterOffset = 0;
3280 pSMB->DataCount = __constant_cpu_to_le32(2);
3281 pSMB->DataOffset =
3282 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3283 compression_state) - 4); /* 84 */
3284 pSMB->SetupCount = 4;
3285 pSMB->SubCommand = __constant_cpu_to_le16(NT_TRANSACT_IOCTL);
3286 pSMB->ParameterCount = 0;
3287 pSMB->FunctionCode = __constant_cpu_to_le32(FSCTL_SET_COMPRESSION);
3288 pSMB->IsFsctl = 1; /* FSCTL */
3289 pSMB->IsRootFlag = 0;
3290 pSMB->Fid = fid; /* file handle always le */
3291 /* 3 byte pad, followed by 2 byte compress state */
3292 pSMB->ByteCount = __constant_cpu_to_le16(5);
3293 inc_rfc1001_len(pSMB, 5);
3294
3295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3297 if (rc)
3298 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3299
3300 cifs_buf_release(pSMB);
3301
3302 /*
3303 * Note: On -EAGAIN error only caller can retry on handle based calls
3304 * since file handle passed in no longer valid.
3305 */
3306 return rc;
3307}
3308
3309
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310#ifdef CONFIG_CIFS_POSIX
3311
3312/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003313static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3314 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315{
3316 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003317 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3318 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3319 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003320/*
3321 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3322 ace->e_perm, ace->e_tag, ace->e_id);
3323*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324
3325 return;
3326}
3327
3328/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003329static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3330 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331{
3332 int size = 0;
3333 int i;
3334 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003335 struct cifs_posix_ace *pACE;
3336 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3337 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338
3339 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3340 return -EOPNOTSUPP;
3341
Steve French790fe572007-07-07 19:25:05 +00003342 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 count = le16_to_cpu(cifs_acl->access_entry_count);
3344 pACE = &cifs_acl->ace_array[0];
3345 size = sizeof(struct cifs_posix_acl);
3346 size += sizeof(struct cifs_posix_ace) * count;
3347 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003348 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003349 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3350 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 return -EINVAL;
3352 }
Steve French790fe572007-07-07 19:25:05 +00003353 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 count = le16_to_cpu(cifs_acl->access_entry_count);
3355 size = sizeof(struct cifs_posix_acl);
3356 size += sizeof(struct cifs_posix_ace) * count;
3357/* skip past access ACEs to get to default ACEs */
3358 pACE = &cifs_acl->ace_array[count];
3359 count = le16_to_cpu(cifs_acl->default_entry_count);
3360 size += sizeof(struct cifs_posix_ace) * count;
3361 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003362 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 return -EINVAL;
3364 } else {
3365 /* illegal type */
3366 return -EINVAL;
3367 }
3368
3369 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003370 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003371 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003372 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 return -ERANGE;
3374 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003375 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003376 for (i = 0; i < count ; i++) {
3377 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3378 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 }
3380 }
3381 return size;
3382}
3383
Steve French50c2f752007-07-13 00:33:32 +00003384static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3385 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386{
3387 __u16 rc = 0; /* 0 = ACL converted ok */
3388
Steve Frenchff7feac2005-11-15 16:45:16 -08003389 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3390 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003392 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 /* Probably no need to le convert -1 on any arch but can not hurt */
3394 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003395 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003396 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003397/*
3398 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3399 ace->e_perm, ace->e_tag, ace->e_id);
3400*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 return rc;
3402}
3403
3404/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003405static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3406 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407{
3408 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003409 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3410 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 int count;
3412 int i;
3413
Steve French790fe572007-07-07 19:25:05 +00003414 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 return 0;
3416
3417 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003418 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3419 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003420 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003421 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3422 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 return 0;
3424 }
3425 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003426 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003427 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve Frenchb1d93352013-11-15 20:41:32 -06003428 cifs_acl->default_entry_count = __constant_cpu_to_le16(0xFFFF);
3429 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003430 cifs_acl->default_entry_count = cpu_to_le16(count);
Steve Frenchb1d93352013-11-15 20:41:32 -06003431 cifs_acl->access_entry_count = __constant_cpu_to_le16(0xFFFF);
3432 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003433 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 return 0;
3435 }
Steve French50c2f752007-07-13 00:33:32 +00003436 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3438 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003439 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 /* ACE not converted */
3441 break;
3442 }
3443 }
Steve French790fe572007-07-07 19:25:05 +00003444 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3446 rc += sizeof(struct cifs_posix_acl);
3447 /* BB add check to make sure ACL does not overflow SMB */
3448 }
3449 return rc;
3450}
3451
3452int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003453CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003454 const unsigned char *searchName,
3455 char *acl_inf, const int buflen, const int acl_type,
3456 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457{
3458/* SMB_QUERY_POSIX_ACL */
3459 TRANSACTION2_QPI_REQ *pSMB = NULL;
3460 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3461 int rc = 0;
3462 int bytes_returned;
3463 int name_len;
3464 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003465
Joe Perchesf96637b2013-05-04 22:12:25 -05003466 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
3468queryAclRetry:
3469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3470 (void **) &pSMBr);
3471 if (rc)
3472 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003473
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3475 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003476 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3477 searchName, PATH_MAX, nls_codepage,
3478 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 name_len++; /* trailing null */
3480 name_len *= 2;
3481 pSMB->FileName[name_len] = 0;
3482 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003483 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 name_len = strnlen(searchName, PATH_MAX);
3485 name_len++; /* trailing null */
3486 strncpy(pSMB->FileName, searchName, name_len);
3487 }
3488
3489 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3490 pSMB->TotalDataCount = 0;
3491 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003492 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 pSMB->MaxDataCount = cpu_to_le16(4000);
3494 pSMB->MaxSetupCount = 0;
3495 pSMB->Reserved = 0;
3496 pSMB->Flags = 0;
3497 pSMB->Timeout = 0;
3498 pSMB->Reserved2 = 0;
3499 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003500 offsetof(struct smb_com_transaction2_qpi_req,
3501 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 pSMB->DataCount = 0;
3503 pSMB->DataOffset = 0;
3504 pSMB->SetupCount = 1;
3505 pSMB->Reserved3 = 0;
3506 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3507 byte_count = params + 1 /* pad */ ;
3508 pSMB->TotalParameterCount = cpu_to_le16(params);
3509 pSMB->ParameterCount = pSMB->TotalParameterCount;
3510 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3511 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003512 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 pSMB->ByteCount = cpu_to_le16(byte_count);
3514
3515 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3516 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003517 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003519 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 } else {
3521 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003522
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003525 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 rc = -EIO; /* bad smb */
3527 else {
3528 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3529 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3530 rc = cifs_copy_posix_acl(acl_inf,
3531 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003532 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 }
3534 }
3535 cifs_buf_release(pSMB);
3536 if (rc == -EAGAIN)
3537 goto queryAclRetry;
3538 return rc;
3539}
3540
3541int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003542CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003543 const unsigned char *fileName,
3544 const char *local_acl, const int buflen,
3545 const int acl_type,
3546 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547{
3548 struct smb_com_transaction2_spi_req *pSMB = NULL;
3549 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3550 char *parm_data;
3551 int name_len;
3552 int rc = 0;
3553 int bytes_returned = 0;
3554 __u16 params, byte_count, data_count, param_offset, offset;
3555
Joe Perchesf96637b2013-05-04 22:12:25 -05003556 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557setAclRetry:
3558 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003559 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 if (rc)
3561 return rc;
3562 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3563 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003564 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3565 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 name_len++; /* trailing null */
3567 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003568 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 name_len = strnlen(fileName, PATH_MAX);
3570 name_len++; /* trailing null */
3571 strncpy(pSMB->FileName, fileName, name_len);
3572 }
3573 params = 6 + name_len;
3574 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003575 /* BB find max SMB size from sess */
3576 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 pSMB->MaxSetupCount = 0;
3578 pSMB->Reserved = 0;
3579 pSMB->Flags = 0;
3580 pSMB->Timeout = 0;
3581 pSMB->Reserved2 = 0;
3582 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003583 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 offset = param_offset + params;
3585 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3586 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3587
3588 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003589 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
Steve French790fe572007-07-07 19:25:05 +00003591 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 rc = -EOPNOTSUPP;
3593 goto setACLerrorExit;
3594 }
3595 pSMB->DataOffset = cpu_to_le16(offset);
3596 pSMB->SetupCount = 1;
3597 pSMB->Reserved3 = 0;
3598 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3599 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3600 byte_count = 3 /* pad */ + params + data_count;
3601 pSMB->DataCount = cpu_to_le16(data_count);
3602 pSMB->TotalDataCount = pSMB->DataCount;
3603 pSMB->ParameterCount = cpu_to_le16(params);
3604 pSMB->TotalParameterCount = pSMB->ParameterCount;
3605 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003606 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 pSMB->ByteCount = cpu_to_le16(byte_count);
3608 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003609 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003610 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003611 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
3613setACLerrorExit:
3614 cifs_buf_release(pSMB);
3615 if (rc == -EAGAIN)
3616 goto setAclRetry;
3617 return rc;
3618}
3619
Steve Frenchf654bac2005-04-28 22:41:04 -07003620/* BB fix tabs in this function FIXME BB */
3621int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003622CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003623 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003624{
Steve French50c2f752007-07-13 00:33:32 +00003625 int rc = 0;
3626 struct smb_t2_qfi_req *pSMB = NULL;
3627 struct smb_t2_qfi_rsp *pSMBr = NULL;
3628 int bytes_returned;
3629 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003630
Joe Perchesf96637b2013-05-04 22:12:25 -05003631 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003632 if (tcon == NULL)
3633 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003634
3635GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003636 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3637 (void **) &pSMBr);
3638 if (rc)
3639 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003640
Steve Frenchad7a2922008-02-07 23:25:02 +00003641 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003642 pSMB->t2.TotalDataCount = 0;
3643 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3644 /* BB find exact max data count below from sess structure BB */
3645 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3646 pSMB->t2.MaxSetupCount = 0;
3647 pSMB->t2.Reserved = 0;
3648 pSMB->t2.Flags = 0;
3649 pSMB->t2.Timeout = 0;
3650 pSMB->t2.Reserved2 = 0;
3651 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3652 Fid) - 4);
3653 pSMB->t2.DataCount = 0;
3654 pSMB->t2.DataOffset = 0;
3655 pSMB->t2.SetupCount = 1;
3656 pSMB->t2.Reserved3 = 0;
3657 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3658 byte_count = params + 1 /* pad */ ;
3659 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3660 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3661 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3662 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003663 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003664 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003665 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003666
Steve French790fe572007-07-07 19:25:05 +00003667 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3668 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3669 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003670 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003671 } else {
3672 /* decode response */
3673 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003674 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003675 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003676 /* If rc should we check for EOPNOSUPP and
3677 disable the srvino flag? or in caller? */
3678 rc = -EIO; /* bad smb */
3679 else {
3680 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3681 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3682 struct file_chattr_info *pfinfo;
3683 /* BB Do we need a cast or hash here ? */
3684 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003685 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003686 rc = -EIO;
3687 goto GetExtAttrOut;
3688 }
3689 pfinfo = (struct file_chattr_info *)
3690 (data_offset + (char *) &pSMBr->hdr.Protocol);
3691 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003692 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003693 }
3694 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003695GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003696 cifs_buf_release(pSMB);
3697 if (rc == -EAGAIN)
3698 goto GetExtAttrRetry;
3699 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003700}
3701
Steve Frenchf654bac2005-04-28 22:41:04 -07003702#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
Jeff Layton79df1ba2010-12-06 12:52:08 -05003704#ifdef CONFIG_CIFS_ACL
3705/*
3706 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3707 * all NT TRANSACTS that we init here have total parm and data under about 400
3708 * bytes (to fit in small cifs buffer size), which is the case so far, it
3709 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3710 * returned setup area) and MaxParameterCount (returned parms size) must be set
3711 * by caller
3712 */
3713static int
3714smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003715 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003716 void **ret_buf)
3717{
3718 int rc;
3719 __u32 temp_offset;
3720 struct smb_com_ntransact_req *pSMB;
3721
3722 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3723 (void **)&pSMB);
3724 if (rc)
3725 return rc;
3726 *ret_buf = (void *)pSMB;
3727 pSMB->Reserved = 0;
3728 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3729 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003730 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003731 pSMB->ParameterCount = pSMB->TotalParameterCount;
3732 pSMB->DataCount = pSMB->TotalDataCount;
3733 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3734 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3735 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3736 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3737 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3738 pSMB->SubCommand = cpu_to_le16(sub_command);
3739 return 0;
3740}
3741
3742static int
3743validate_ntransact(char *buf, char **ppparm, char **ppdata,
3744 __u32 *pparmlen, __u32 *pdatalen)
3745{
3746 char *end_of_smb;
3747 __u32 data_count, data_offset, parm_count, parm_offset;
3748 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003749 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003750
3751 *pdatalen = 0;
3752 *pparmlen = 0;
3753
3754 if (buf == NULL)
3755 return -EINVAL;
3756
3757 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3758
Jeff Layton820a8032011-05-04 08:05:26 -04003759 bcc = get_bcc(&pSMBr->hdr);
3760 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003761 (char *)&pSMBr->ByteCount;
3762
3763 data_offset = le32_to_cpu(pSMBr->DataOffset);
3764 data_count = le32_to_cpu(pSMBr->DataCount);
3765 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3766 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3767
3768 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3769 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3770
3771 /* should we also check that parm and data areas do not overlap? */
3772 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003773 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003774 return -EINVAL;
3775 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003776 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003777 return -EINVAL;
3778 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003779 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003780 return -EINVAL;
3781 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003782 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3783 *ppdata, data_count, (data_count + *ppdata),
3784 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003785 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003786 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003787 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003788 return -EINVAL;
3789 }
3790 *pdatalen = data_count;
3791 *pparmlen = parm_count;
3792 return 0;
3793}
3794
Steve French0a4b92c2006-01-12 15:44:21 -08003795/* Get Security Descriptor (by handle) from remote server for a file or dir */
3796int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003797CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003798 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003799{
3800 int rc = 0;
3801 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003802 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003803 struct kvec iov[1];
3804
Joe Perchesf96637b2013-05-04 22:12:25 -05003805 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003806
Steve French630f3f0c2007-10-25 21:17:17 +00003807 *pbuflen = 0;
3808 *acl_inf = NULL;
3809
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003810 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003811 8 /* parm len */, tcon, (void **) &pSMB);
3812 if (rc)
3813 return rc;
3814
3815 pSMB->MaxParameterCount = cpu_to_le32(4);
3816 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3817 pSMB->MaxSetupCount = 0;
3818 pSMB->Fid = fid; /* file handle always le */
3819 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3820 CIFS_ACL_DACL);
3821 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003822 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003823 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003824 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003825
Steve Frencha761ac52007-10-18 21:45:27 +00003826 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003827 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003828 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003829 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003830 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003831 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003832 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003833 __u32 parm_len;
3834 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003835 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003836 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003837
3838/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003839 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003840 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003841 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003842 goto qsec_out;
3843 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3844
Joe Perchesf96637b2013-05-04 22:12:25 -05003845 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3846 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003847
3848 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3849 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003850 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003851 goto qsec_out;
3852 }
3853
3854/* BB check that data area is minimum length and as big as acl_len */
3855
Steve Frenchaf6f4612007-10-16 18:40:37 +00003856 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003857 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003858 cifs_dbg(VFS, "acl length %d does not match %d\n",
3859 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003860 if (*pbuflen > acl_len)
3861 *pbuflen = acl_len;
3862 }
Steve French0a4b92c2006-01-12 15:44:21 -08003863
Steve French630f3f0c2007-10-25 21:17:17 +00003864 /* check if buffer is big enough for the acl
3865 header followed by the smallest SID */
3866 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3867 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003868 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003869 rc = -EINVAL;
3870 *pbuflen = 0;
3871 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003872 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003873 if (*acl_inf == NULL) {
3874 *pbuflen = 0;
3875 rc = -ENOMEM;
3876 }
Steve French630f3f0c2007-10-25 21:17:17 +00003877 }
Steve French0a4b92c2006-01-12 15:44:21 -08003878 }
3879qsec_out:
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01003880 free_rsp_buf(buf_type, iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003881/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003882 return rc;
3883}
Steve French97837582007-12-31 07:47:21 +00003884
3885int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003886CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003887 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003888{
3889 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3890 int rc = 0;
3891 int bytes_returned = 0;
3892 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003893 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003894
3895setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003896 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003897 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003898 return rc;
Steve French97837582007-12-31 07:47:21 +00003899
3900 pSMB->MaxSetupCount = 0;
3901 pSMB->Reserved = 0;
3902
3903 param_count = 8;
3904 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3905 data_count = acllen;
3906 data_offset = param_offset + param_count;
3907 byte_count = 3 /* pad */ + param_count;
3908
3909 pSMB->DataCount = cpu_to_le32(data_count);
3910 pSMB->TotalDataCount = pSMB->DataCount;
3911 pSMB->MaxParameterCount = cpu_to_le32(4);
3912 pSMB->MaxDataCount = cpu_to_le32(16384);
3913 pSMB->ParameterCount = cpu_to_le32(param_count);
3914 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3915 pSMB->TotalParameterCount = pSMB->ParameterCount;
3916 pSMB->DataOffset = cpu_to_le32(data_offset);
3917 pSMB->SetupCount = 0;
3918 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3919 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3920
3921 pSMB->Fid = fid; /* file handle always le */
3922 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003923 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003924
3925 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003926 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3927 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003928 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003929 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003930 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003931
3932 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3933 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3934
Joe Perchesf96637b2013-05-04 22:12:25 -05003935 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3936 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003937 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003938 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003939 cifs_buf_release(pSMB);
3940
3941 if (rc == -EAGAIN)
3942 goto setCifsAclRetry;
3943
3944 return (rc);
3945}
3946
Jeff Layton79df1ba2010-12-06 12:52:08 -05003947#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003948
Steve French6b8edfe2005-08-23 20:26:03 -07003949/* Legacy Query Path Information call for lookup to old servers such
3950 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003951int
3952SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3953 const char *search_name, FILE_ALL_INFO *data,
3954 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003955{
Steve Frenchad7a2922008-02-07 23:25:02 +00003956 QUERY_INFORMATION_REQ *pSMB;
3957 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003958 int rc = 0;
3959 int bytes_returned;
3960 int name_len;
3961
Joe Perchesf96637b2013-05-04 22:12:25 -05003962 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003963QInfRetry:
3964 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003965 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003966 if (rc)
3967 return rc;
3968
3969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3970 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003971 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003972 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003973 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003974 name_len++; /* trailing null */
3975 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003976 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003977 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003978 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003979 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003980 }
3981 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003982 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003983 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003984 pSMB->ByteCount = cpu_to_le16(name_len);
3985
3986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003988 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003989 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003990 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003991 struct timespec ts;
3992 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003993
3994 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003995 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003996 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003997 ts.tv_nsec = 0;
3998 ts.tv_sec = time;
3999 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004000 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4001 data->LastWriteTime = data->ChangeTime;
4002 data->LastAccessTime = 0;
4003 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004004 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004005 data->EndOfFile = data->AllocationSize;
4006 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004007 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004008 } else
4009 rc = -EIO; /* bad buffer passed in */
4010
4011 cifs_buf_release(pSMB);
4012
4013 if (rc == -EAGAIN)
4014 goto QInfRetry;
4015
4016 return rc;
4017}
4018
Jeff Laytonbcd53572010-02-12 07:44:16 -05004019int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004020CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004021 u16 netfid, FILE_ALL_INFO *pFindData)
4022{
4023 struct smb_t2_qfi_req *pSMB = NULL;
4024 struct smb_t2_qfi_rsp *pSMBr = NULL;
4025 int rc = 0;
4026 int bytes_returned;
4027 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004028
Jeff Laytonbcd53572010-02-12 07:44:16 -05004029QFileInfoRetry:
4030 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4031 (void **) &pSMBr);
4032 if (rc)
4033 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004034
Jeff Laytonbcd53572010-02-12 07:44:16 -05004035 params = 2 /* level */ + 2 /* fid */;
4036 pSMB->t2.TotalDataCount = 0;
4037 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4038 /* BB find exact max data count below from sess structure BB */
4039 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4040 pSMB->t2.MaxSetupCount = 0;
4041 pSMB->t2.Reserved = 0;
4042 pSMB->t2.Flags = 0;
4043 pSMB->t2.Timeout = 0;
4044 pSMB->t2.Reserved2 = 0;
4045 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4046 Fid) - 4);
4047 pSMB->t2.DataCount = 0;
4048 pSMB->t2.DataOffset = 0;
4049 pSMB->t2.SetupCount = 1;
4050 pSMB->t2.Reserved3 = 0;
4051 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4052 byte_count = params + 1 /* pad */ ;
4053 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4054 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4055 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4056 pSMB->Pad = 0;
4057 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004058 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004059 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004060
4061 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4062 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4063 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004064 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004065 } else { /* decode response */
4066 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4067
4068 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4069 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004070 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004071 rc = -EIO; /* bad smb */
4072 else if (pFindData) {
4073 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4074 memcpy((char *) pFindData,
4075 (char *) &pSMBr->hdr.Protocol +
4076 data_offset, sizeof(FILE_ALL_INFO));
4077 } else
4078 rc = -ENOMEM;
4079 }
4080 cifs_buf_release(pSMB);
4081 if (rc == -EAGAIN)
4082 goto QFileInfoRetry;
4083
4084 return rc;
4085}
Steve French6b8edfe2005-08-23 20:26:03 -07004086
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004088CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004089 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004090 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004091 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004093 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 TRANSACTION2_QPI_REQ *pSMB = NULL;
4095 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4096 int rc = 0;
4097 int bytes_returned;
4098 int name_len;
4099 __u16 params, byte_count;
4100
Joe Perchesf96637b2013-05-04 22:12:25 -05004101 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102QPathInfoRetry:
4103 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4104 (void **) &pSMBr);
4105 if (rc)
4106 return rc;
4107
4108 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4109 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004110 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004111 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 name_len++; /* trailing null */
4113 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004114 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004115 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004117 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 }
4119
Steve French50c2f752007-07-13 00:33:32 +00004120 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 pSMB->TotalDataCount = 0;
4122 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004123 /* BB find exact max SMB PDU from sess structure BB */
4124 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 pSMB->MaxSetupCount = 0;
4126 pSMB->Reserved = 0;
4127 pSMB->Flags = 0;
4128 pSMB->Timeout = 0;
4129 pSMB->Reserved2 = 0;
4130 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004131 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 pSMB->DataCount = 0;
4133 pSMB->DataOffset = 0;
4134 pSMB->SetupCount = 1;
4135 pSMB->Reserved3 = 0;
4136 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4137 byte_count = params + 1 /* pad */ ;
4138 pSMB->TotalParameterCount = cpu_to_le16(params);
4139 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004140 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004141 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4142 else
4143 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004145 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 pSMB->ByteCount = cpu_to_le16(byte_count);
4147
4148 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4149 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4150 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004151 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 } else { /* decode response */
4153 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4154
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004155 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4156 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004157 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004159 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004160 rc = -EIO; /* 24 or 26 expected but we do not read
4161 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004162 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004163 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004165
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004166 /*
4167 * On legacy responses we do not read the last field,
4168 * EAsize, fortunately since it varies by subdialect and
4169 * also note it differs on Set vs Get, ie two bytes or 4
4170 * bytes depending but we don't care here.
4171 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004172 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004173 size = sizeof(FILE_INFO_STANDARD);
4174 else
4175 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004176 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004177 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 } else
4179 rc = -ENOMEM;
4180 }
4181 cifs_buf_release(pSMB);
4182 if (rc == -EAGAIN)
4183 goto QPathInfoRetry;
4184
4185 return rc;
4186}
4187
4188int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004189CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004190 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4191{
4192 struct smb_t2_qfi_req *pSMB = NULL;
4193 struct smb_t2_qfi_rsp *pSMBr = NULL;
4194 int rc = 0;
4195 int bytes_returned;
4196 __u16 params, byte_count;
4197
4198UnixQFileInfoRetry:
4199 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4200 (void **) &pSMBr);
4201 if (rc)
4202 return rc;
4203
4204 params = 2 /* level */ + 2 /* fid */;
4205 pSMB->t2.TotalDataCount = 0;
4206 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4207 /* BB find exact max data count below from sess structure BB */
4208 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4209 pSMB->t2.MaxSetupCount = 0;
4210 pSMB->t2.Reserved = 0;
4211 pSMB->t2.Flags = 0;
4212 pSMB->t2.Timeout = 0;
4213 pSMB->t2.Reserved2 = 0;
4214 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4215 Fid) - 4);
4216 pSMB->t2.DataCount = 0;
4217 pSMB->t2.DataOffset = 0;
4218 pSMB->t2.SetupCount = 1;
4219 pSMB->t2.Reserved3 = 0;
4220 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4221 byte_count = params + 1 /* pad */ ;
4222 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4223 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4224 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4225 pSMB->Pad = 0;
4226 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004227 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004228 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004229
4230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4231 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4232 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004233 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004234 } else { /* decode response */
4235 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4236
Jeff Layton820a8032011-05-04 08:05:26 -04004237 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004238 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 -05004239 rc = -EIO; /* bad smb */
4240 } else {
4241 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4242 memcpy((char *) pFindData,
4243 (char *) &pSMBr->hdr.Protocol +
4244 data_offset,
4245 sizeof(FILE_UNIX_BASIC_INFO));
4246 }
4247 }
4248
4249 cifs_buf_release(pSMB);
4250 if (rc == -EAGAIN)
4251 goto UnixQFileInfoRetry;
4252
4253 return rc;
4254}
4255
4256int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004257CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004259 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004260 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261{
4262/* SMB_QUERY_FILE_UNIX_BASIC */
4263 TRANSACTION2_QPI_REQ *pSMB = NULL;
4264 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4265 int rc = 0;
4266 int bytes_returned = 0;
4267 int name_len;
4268 __u16 params, byte_count;
4269
Joe Perchesf96637b2013-05-04 22:12:25 -05004270 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271UnixQPathInfoRetry:
4272 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4273 (void **) &pSMBr);
4274 if (rc)
4275 return rc;
4276
4277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4278 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004279 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4280 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 name_len++; /* trailing null */
4282 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004283 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 name_len = strnlen(searchName, PATH_MAX);
4285 name_len++; /* trailing null */
4286 strncpy(pSMB->FileName, searchName, name_len);
4287 }
4288
Steve French50c2f752007-07-13 00:33:32 +00004289 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 pSMB->TotalDataCount = 0;
4291 pSMB->MaxParameterCount = cpu_to_le16(2);
4292 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004293 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 pSMB->MaxSetupCount = 0;
4295 pSMB->Reserved = 0;
4296 pSMB->Flags = 0;
4297 pSMB->Timeout = 0;
4298 pSMB->Reserved2 = 0;
4299 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004300 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 pSMB->DataCount = 0;
4302 pSMB->DataOffset = 0;
4303 pSMB->SetupCount = 1;
4304 pSMB->Reserved3 = 0;
4305 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4306 byte_count = params + 1 /* pad */ ;
4307 pSMB->TotalParameterCount = cpu_to_le16(params);
4308 pSMB->ParameterCount = pSMB->TotalParameterCount;
4309 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4310 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004311 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 pSMB->ByteCount = cpu_to_le16(byte_count);
4313
4314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4315 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4316 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004317 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 } else { /* decode response */
4319 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4320
Jeff Layton820a8032011-05-04 08:05:26 -04004321 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004322 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 -07004323 rc = -EIO; /* bad smb */
4324 } else {
4325 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4326 memcpy((char *) pFindData,
4327 (char *) &pSMBr->hdr.Protocol +
4328 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004329 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 }
4331 }
4332 cifs_buf_release(pSMB);
4333 if (rc == -EAGAIN)
4334 goto UnixQPathInfoRetry;
4335
4336 return rc;
4337}
4338
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339/* xid, tcon, searchName and codepage are input parms, rest are returned */
4340int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004341CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004342 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004343 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004344 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345{
4346/* level 257 SMB_ */
4347 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4348 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004349 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 int rc = 0;
4351 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004352 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004354 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Joe Perchesf96637b2013-05-04 22:12:25 -05004356 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357
4358findFirstRetry:
4359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360 (void **) &pSMBr);
4361 if (rc)
4362 return rc;
4363
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004364 nls_codepage = cifs_sb->local_nls;
4365 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4366
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4368 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004369 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4370 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004371 /* We can not add the asterik earlier in case
4372 it got remapped to 0xF03A as if it were part of the
4373 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004375 if (msearch) {
4376 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4377 pSMB->FileName[name_len+1] = 0;
4378 pSMB->FileName[name_len+2] = '*';
4379 pSMB->FileName[name_len+3] = 0;
4380 name_len += 4; /* now the trailing null */
4381 /* null terminate just in case */
4382 pSMB->FileName[name_len] = 0;
4383 pSMB->FileName[name_len+1] = 0;
4384 name_len += 2;
4385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 } else { /* BB add check for overrun of SMB buf BB */
4387 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004389 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 free buffer exit; BB */
4391 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004392 if (msearch) {
4393 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4394 pSMB->FileName[name_len+1] = '*';
4395 pSMB->FileName[name_len+2] = 0;
4396 name_len += 3;
4397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 }
4399
4400 params = 12 + name_len /* includes null */ ;
4401 pSMB->TotalDataCount = 0; /* no EAs */
4402 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004403 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 pSMB->MaxSetupCount = 0;
4405 pSMB->Reserved = 0;
4406 pSMB->Flags = 0;
4407 pSMB->Timeout = 0;
4408 pSMB->Reserved2 = 0;
4409 byte_count = params + 1 /* pad */ ;
4410 pSMB->TotalParameterCount = cpu_to_le16(params);
4411 pSMB->ParameterCount = pSMB->TotalParameterCount;
4412 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004413 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4414 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 pSMB->DataCount = 0;
4416 pSMB->DataOffset = 0;
4417 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4418 pSMB->Reserved3 = 0;
4419 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4420 pSMB->SearchAttributes =
4421 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4422 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004423 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004424 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4426
4427 /* BB what should we set StorageType to? Does it matter? BB */
4428 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004429 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 pSMB->ByteCount = cpu_to_le16(byte_count);
4431
4432 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4433 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004434 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Steve French88274812006-03-09 22:21:45 +00004436 if (rc) {/* BB add logic to retry regular search if Unix search
4437 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004439 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004440
Steve French88274812006-03-09 22:21:45 +00004441 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442
4443 /* BB eventually could optimize out free and realloc of buf */
4444 /* for this case */
4445 if (rc == -EAGAIN)
4446 goto findFirstRetry;
4447 } else { /* decode response */
4448 /* BB remember to free buffer if error BB */
4449 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004450 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004451 unsigned int lnoff;
4452
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004454 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 else
Steve French4b18f2a2008-04-29 00:06:05 +00004456 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457
4458 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004459 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004460 psrch_inf->srch_entries_start =
4461 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4464 le16_to_cpu(pSMBr->t2.ParameterOffset));
4465
Steve French790fe572007-07-07 19:25:05 +00004466 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004467 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 else
Steve French4b18f2a2008-04-29 00:06:05 +00004469 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470
Steve French50c2f752007-07-13 00:33:32 +00004471 psrch_inf->entries_in_buffer =
4472 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004473 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004475 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004476 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004477 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004478 psrch_inf->last_entry = NULL;
4479 return rc;
4480 }
4481
Steve French0752f152008-10-07 20:03:33 +00004482 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004483 lnoff;
4484
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004485 if (pnetfid)
4486 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 } else {
4488 cifs_buf_release(pSMB);
4489 }
4490 }
4491
4492 return rc;
4493}
4494
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004495int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4496 __u16 searchHandle, __u16 search_flags,
4497 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498{
4499 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4500 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004501 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 char *response_data;
4503 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004504 int bytes_returned;
4505 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 __u16 params, byte_count;
4507
Joe Perchesf96637b2013-05-04 22:12:25 -05004508 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
Steve French4b18f2a2008-04-29 00:06:05 +00004510 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 return -ENOENT;
4512
4513 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4514 (void **) &pSMBr);
4515 if (rc)
4516 return rc;
4517
Steve French50c2f752007-07-13 00:33:32 +00004518 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 byte_count = 0;
4520 pSMB->TotalDataCount = 0; /* no EAs */
4521 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004522 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 pSMB->MaxSetupCount = 0;
4524 pSMB->Reserved = 0;
4525 pSMB->Flags = 0;
4526 pSMB->Timeout = 0;
4527 pSMB->Reserved2 = 0;
4528 pSMB->ParameterOffset = cpu_to_le16(
4529 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4530 pSMB->DataCount = 0;
4531 pSMB->DataOffset = 0;
4532 pSMB->SetupCount = 1;
4533 pSMB->Reserved3 = 0;
4534 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4535 pSMB->SearchHandle = searchHandle; /* always kept as le */
4536 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004537 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4539 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004540 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541
4542 name_len = psrch_inf->resume_name_len;
4543 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004544 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4546 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004547 /* 14 byte parm len above enough for 2 byte null terminator */
4548 pSMB->ResumeFileName[name_len] = 0;
4549 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 } else {
4551 rc = -EINVAL;
4552 goto FNext2_err_exit;
4553 }
4554 byte_count = params + 1 /* pad */ ;
4555 pSMB->TotalParameterCount = cpu_to_le16(params);
4556 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004557 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004559
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4561 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004562 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 if (rc) {
4564 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004565 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004566 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004567 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004569 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 } else { /* decode response */
4571 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004572
Steve French790fe572007-07-07 19:25:05 +00004573 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004574 unsigned int lnoff;
4575
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 /* BB fixme add lock for file (srch_info) struct here */
4577 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004578 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 else
Steve French4b18f2a2008-04-29 00:06:05 +00004580 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 response_data = (char *) &pSMBr->hdr.Protocol +
4582 le16_to_cpu(pSMBr->t2.ParameterOffset);
4583 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4584 response_data = (char *)&pSMBr->hdr.Protocol +
4585 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004586 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004587 cifs_small_buf_release(
4588 psrch_inf->ntwrk_buf_start);
4589 else
4590 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 psrch_inf->srch_entries_start = response_data;
4592 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004593 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004594 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004595 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 else
Steve French4b18f2a2008-04-29 00:06:05 +00004597 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004598 psrch_inf->entries_in_buffer =
4599 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 psrch_inf->index_of_last_entry +=
4601 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004602 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004603 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004604 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004605 psrch_inf->last_entry = NULL;
4606 return rc;
4607 } else
4608 psrch_inf->last_entry =
4609 psrch_inf->srch_entries_start + lnoff;
4610
Joe Perchesf96637b2013-05-04 22:12:25 -05004611/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4612 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613
4614 /* BB fixme add unlock here */
4615 }
4616
4617 }
4618
4619 /* BB On error, should we leave previous search buf (and count and
4620 last entry fields) intact or free the previous one? */
4621
4622 /* Note: On -EAGAIN error only caller can retry on handle based calls
4623 since file handle passed in no longer valid */
4624FNext2_err_exit:
4625 if (rc != 0)
4626 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 return rc;
4628}
4629
4630int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004631CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004632 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633{
4634 int rc = 0;
4635 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
Joe Perchesf96637b2013-05-04 22:12:25 -05004637 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4639
4640 /* no sense returning error if session restarted
4641 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004642 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 return 0;
4644 if (rc)
4645 return rc;
4646
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 pSMB->FileID = searchHandle;
4648 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004649 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004650 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004651 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004652
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004653 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654
4655 /* Since session is dead, search handle closed on server already */
4656 if (rc == -EAGAIN)
4657 rc = 0;
4658
4659 return rc;
4660}
4661
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004663CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004664 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004665 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666{
4667 int rc = 0;
4668 TRANSACTION2_QPI_REQ *pSMB = NULL;
4669 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4670 int name_len, bytes_returned;
4671 __u16 params, byte_count;
4672
Joe Perchesf96637b2013-05-04 22:12:25 -05004673 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004674 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004675 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676
4677GetInodeNumberRetry:
4678 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004679 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 if (rc)
4681 return rc;
4682
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4684 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004685 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004686 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004687 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 name_len++; /* trailing null */
4689 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004690 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004691 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004693 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 }
4695
4696 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4697 pSMB->TotalDataCount = 0;
4698 pSMB->MaxParameterCount = cpu_to_le16(2);
4699 /* BB find exact max data count below from sess structure BB */
4700 pSMB->MaxDataCount = cpu_to_le16(4000);
4701 pSMB->MaxSetupCount = 0;
4702 pSMB->Reserved = 0;
4703 pSMB->Flags = 0;
4704 pSMB->Timeout = 0;
4705 pSMB->Reserved2 = 0;
4706 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004707 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 pSMB->DataCount = 0;
4709 pSMB->DataOffset = 0;
4710 pSMB->SetupCount = 1;
4711 pSMB->Reserved3 = 0;
4712 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4713 byte_count = params + 1 /* pad */ ;
4714 pSMB->TotalParameterCount = cpu_to_le16(params);
4715 pSMB->ParameterCount = pSMB->TotalParameterCount;
4716 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4717 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004718 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 pSMB->ByteCount = cpu_to_le16(byte_count);
4720
4721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4723 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004724 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 } else {
4726 /* decode response */
4727 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004729 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 /* If rc should we check for EOPNOSUPP and
4731 disable the srvino flag? or in caller? */
4732 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004733 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4735 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004736 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004738 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004739 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 rc = -EIO;
4741 goto GetInodeNumOut;
4742 }
4743 pfinfo = (struct file_internal_info *)
4744 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004745 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 }
4747 }
4748GetInodeNumOut:
4749 cifs_buf_release(pSMB);
4750 if (rc == -EAGAIN)
4751 goto GetInodeNumberRetry;
4752 return rc;
4753}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754
Igor Mammedovfec45852008-05-16 13:06:30 +04004755/* parses DFS refferal V3 structure
4756 * caller is responsible for freeing target_nodes
4757 * returns:
4758 * on success - 0
4759 * on failure - errno
4760 */
4761static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004762parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004763 unsigned int *num_of_nodes,
4764 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004765 const struct nls_table *nls_codepage, int remap,
4766 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004767{
4768 int i, rc = 0;
4769 char *data_end;
4770 bool is_unicode;
4771 struct dfs_referral_level_3 *ref;
4772
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004773 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4774 is_unicode = true;
4775 else
4776 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004777 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4778
4779 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004780 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4781 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004782 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004783 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004784 }
4785
4786 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004787 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004788 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4789 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004790 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004791 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004792 }
4793
4794 /* get the upper boundary of the resp buffer */
4795 data_end = (char *)(&(pSMBr->PathConsumed)) +
4796 le16_to_cpu(pSMBr->t2.DataCount);
4797
Joe Perchesf96637b2013-05-04 22:12:25 -05004798 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4799 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004800
Joe Perchesf96637b2013-05-04 22:12:25 -05004801 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4802 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004803 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004804 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004805 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004806 }
4807
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004808 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004809 for (i = 0; i < *num_of_nodes; i++) {
4810 char *temp;
4811 int max_len;
4812 struct dfs_info3_param *node = (*target_nodes)+i;
4813
Steve French0e0d2cf2009-05-01 05:27:32 +00004814 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004815 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004816 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4817 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004818 if (tmp == NULL) {
4819 rc = -ENOMEM;
4820 goto parse_DFS_referrals_exit;
4821 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004822 cifsConvertToUTF16((__le16 *) tmp, searchName,
4823 PATH_MAX, nls_codepage, remap);
4824 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004825 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004826 nls_codepage);
4827 kfree(tmp);
4828 } else
4829 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4830
Igor Mammedovfec45852008-05-16 13:06:30 +04004831 node->server_type = le16_to_cpu(ref->ServerType);
4832 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4833
4834 /* copy DfsPath */
4835 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4836 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004837 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4838 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004839 if (!node->path_name) {
4840 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004841 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004842 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004843
4844 /* copy link target UNC */
4845 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4846 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004847 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4848 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004849 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004850 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004851 goto parse_DFS_referrals_exit;
4852 }
4853
4854 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004855 }
4856
Steve Frencha1fe78f2008-05-16 18:48:38 +00004857parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004858 if (rc) {
4859 free_dfs_info_array(*target_nodes, *num_of_nodes);
4860 *target_nodes = NULL;
4861 *num_of_nodes = 0;
4862 }
4863 return rc;
4864}
4865
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004867CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004868 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004869 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004870 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871{
4872/* TRANS2_GET_DFS_REFERRAL */
4873 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4874 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 int rc = 0;
4876 int bytes_returned;
4877 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004879 *num_of_nodes = 0;
4880 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881
Joe Perchesf96637b2013-05-04 22:12:25 -05004882 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 if (ses == NULL)
4884 return -ENODEV;
4885getDFSRetry:
4886 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4887 (void **) &pSMBr);
4888 if (rc)
4889 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004890
4891 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004892 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004893 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 pSMB->hdr.Tid = ses->ipc_tid;
4895 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004896 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004898 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900
4901 if (ses->capabilities & CAP_UNICODE) {
4902 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4903 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004904 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004905 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004906 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 name_len++; /* trailing null */
4908 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004909 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004910 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004912 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 }
4914
Jeff Layton38d77c52013-05-26 07:01:00 -04004915 if (ses->server && ses->server->sign)
4916 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004917
Steve French50c2f752007-07-13 00:33:32 +00004918 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004919
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 params = 2 /* level */ + name_len /*includes null */ ;
4921 pSMB->TotalDataCount = 0;
4922 pSMB->DataCount = 0;
4923 pSMB->DataOffset = 0;
4924 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004925 /* BB find exact max SMB PDU from sess structure BB */
4926 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 pSMB->MaxSetupCount = 0;
4928 pSMB->Reserved = 0;
4929 pSMB->Flags = 0;
4930 pSMB->Timeout = 0;
4931 pSMB->Reserved2 = 0;
4932 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004933 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 pSMB->SetupCount = 1;
4935 pSMB->Reserved3 = 0;
4936 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4937 byte_count = params + 3 /* pad */ ;
4938 pSMB->ParameterCount = cpu_to_le16(params);
4939 pSMB->TotalParameterCount = pSMB->ParameterCount;
4940 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004941 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 pSMB->ByteCount = cpu_to_le16(byte_count);
4943
4944 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4946 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004947 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004948 goto GetDFSRefExit;
4949 }
4950 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004952 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004953 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004954 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004955 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004957
Joe Perchesf96637b2013-05-04 22:12:25 -05004958 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4959 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004960
4961 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004962 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004963 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004964 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004965
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004967 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968
4969 if (rc == -EAGAIN)
4970 goto getDFSRetry;
4971
4972 return rc;
4973}
4974
Steve French20962432005-09-21 22:05:57 -07004975/* Query File System Info such as free space to old servers such as Win 9x */
4976int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004977SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4978 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004979{
4980/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4981 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4982 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4983 FILE_SYSTEM_ALLOC_INFO *response_data;
4984 int rc = 0;
4985 int bytes_returned = 0;
4986 __u16 params, byte_count;
4987
Joe Perchesf96637b2013-05-04 22:12:25 -05004988 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004989oldQFSInfoRetry:
4990 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4991 (void **) &pSMBr);
4992 if (rc)
4993 return rc;
Steve French20962432005-09-21 22:05:57 -07004994
4995 params = 2; /* level */
4996 pSMB->TotalDataCount = 0;
4997 pSMB->MaxParameterCount = cpu_to_le16(2);
4998 pSMB->MaxDataCount = cpu_to_le16(1000);
4999 pSMB->MaxSetupCount = 0;
5000 pSMB->Reserved = 0;
5001 pSMB->Flags = 0;
5002 pSMB->Timeout = 0;
5003 pSMB->Reserved2 = 0;
5004 byte_count = params + 1 /* pad */ ;
5005 pSMB->TotalParameterCount = cpu_to_le16(params);
5006 pSMB->ParameterCount = pSMB->TotalParameterCount;
5007 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5008 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5009 pSMB->DataCount = 0;
5010 pSMB->DataOffset = 0;
5011 pSMB->SetupCount = 1;
5012 pSMB->Reserved3 = 0;
5013 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5014 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005015 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005016 pSMB->ByteCount = cpu_to_le16(byte_count);
5017
5018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5020 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005021 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005022 } else { /* decode response */
5023 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5024
Jeff Layton820a8032011-05-04 08:05:26 -04005025 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005026 rc = -EIO; /* bad smb */
5027 else {
5028 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005029 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005030 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005031
Steve French50c2f752007-07-13 00:33:32 +00005032 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005033 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5034 FSData->f_bsize =
5035 le16_to_cpu(response_data->BytesPerSector) *
5036 le32_to_cpu(response_data->
5037 SectorsPerAllocationUnit);
5038 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005039 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005040 FSData->f_bfree = FSData->f_bavail =
5041 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005042 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5043 (unsigned long long)FSData->f_blocks,
5044 (unsigned long long)FSData->f_bfree,
5045 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005046 }
5047 }
5048 cifs_buf_release(pSMB);
5049
5050 if (rc == -EAGAIN)
5051 goto oldQFSInfoRetry;
5052
5053 return rc;
5054}
5055
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005057CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5058 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059{
5060/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5061 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5062 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5063 FILE_SYSTEM_INFO *response_data;
5064 int rc = 0;
5065 int bytes_returned = 0;
5066 __u16 params, byte_count;
5067
Joe Perchesf96637b2013-05-04 22:12:25 -05005068 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069QFSInfoRetry:
5070 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5071 (void **) &pSMBr);
5072 if (rc)
5073 return rc;
5074
5075 params = 2; /* level */
5076 pSMB->TotalDataCount = 0;
5077 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005078 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 pSMB->MaxSetupCount = 0;
5080 pSMB->Reserved = 0;
5081 pSMB->Flags = 0;
5082 pSMB->Timeout = 0;
5083 pSMB->Reserved2 = 0;
5084 byte_count = params + 1 /* pad */ ;
5085 pSMB->TotalParameterCount = cpu_to_le16(params);
5086 pSMB->ParameterCount = pSMB->TotalParameterCount;
5087 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005088 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 pSMB->DataCount = 0;
5090 pSMB->DataOffset = 0;
5091 pSMB->SetupCount = 1;
5092 pSMB->Reserved3 = 0;
5093 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5094 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005095 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 pSMB->ByteCount = cpu_to_le16(byte_count);
5097
5098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5100 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005101 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104
Jeff Layton820a8032011-05-04 08:05:26 -04005105 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 rc = -EIO; /* bad smb */
5107 else {
5108 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109
5110 response_data =
5111 (FILE_SYSTEM_INFO
5112 *) (((char *) &pSMBr->hdr.Protocol) +
5113 data_offset);
5114 FSData->f_bsize =
5115 le32_to_cpu(response_data->BytesPerSector) *
5116 le32_to_cpu(response_data->
5117 SectorsPerAllocationUnit);
5118 FSData->f_blocks =
5119 le64_to_cpu(response_data->TotalAllocationUnits);
5120 FSData->f_bfree = FSData->f_bavail =
5121 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005122 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5123 (unsigned long long)FSData->f_blocks,
5124 (unsigned long long)FSData->f_bfree,
5125 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 }
5127 }
5128 cifs_buf_release(pSMB);
5129
5130 if (rc == -EAGAIN)
5131 goto QFSInfoRetry;
5132
5133 return rc;
5134}
5135
5136int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005137CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138{
5139/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5140 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5141 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5142 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5143 int rc = 0;
5144 int bytes_returned = 0;
5145 __u16 params, byte_count;
5146
Joe Perchesf96637b2013-05-04 22:12:25 -05005147 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148QFSAttributeRetry:
5149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5150 (void **) &pSMBr);
5151 if (rc)
5152 return rc;
5153
5154 params = 2; /* level */
5155 pSMB->TotalDataCount = 0;
5156 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005157 /* BB find exact max SMB PDU from sess structure BB */
5158 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 pSMB->MaxSetupCount = 0;
5160 pSMB->Reserved = 0;
5161 pSMB->Flags = 0;
5162 pSMB->Timeout = 0;
5163 pSMB->Reserved2 = 0;
5164 byte_count = params + 1 /* pad */ ;
5165 pSMB->TotalParameterCount = cpu_to_le16(params);
5166 pSMB->ParameterCount = pSMB->TotalParameterCount;
5167 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005168 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 pSMB->DataCount = 0;
5170 pSMB->DataOffset = 0;
5171 pSMB->SetupCount = 1;
5172 pSMB->Reserved3 = 0;
5173 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5174 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005175 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 pSMB->ByteCount = cpu_to_le16(byte_count);
5177
5178 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5179 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5180 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005181 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 } else { /* decode response */
5183 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5184
Jeff Layton820a8032011-05-04 08:05:26 -04005185 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005186 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 rc = -EIO; /* bad smb */
5188 } else {
5189 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5190 response_data =
5191 (FILE_SYSTEM_ATTRIBUTE_INFO
5192 *) (((char *) &pSMBr->hdr.Protocol) +
5193 data_offset);
5194 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005195 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 }
5197 }
5198 cifs_buf_release(pSMB);
5199
5200 if (rc == -EAGAIN)
5201 goto QFSAttributeRetry;
5202
5203 return rc;
5204}
5205
5206int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005207CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208{
5209/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5210 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5211 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5212 FILE_SYSTEM_DEVICE_INFO *response_data;
5213 int rc = 0;
5214 int bytes_returned = 0;
5215 __u16 params, byte_count;
5216
Joe Perchesf96637b2013-05-04 22:12:25 -05005217 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218QFSDeviceRetry:
5219 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5220 (void **) &pSMBr);
5221 if (rc)
5222 return rc;
5223
5224 params = 2; /* level */
5225 pSMB->TotalDataCount = 0;
5226 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005227 /* BB find exact max SMB PDU from sess structure BB */
5228 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 pSMB->MaxSetupCount = 0;
5230 pSMB->Reserved = 0;
5231 pSMB->Flags = 0;
5232 pSMB->Timeout = 0;
5233 pSMB->Reserved2 = 0;
5234 byte_count = params + 1 /* pad */ ;
5235 pSMB->TotalParameterCount = cpu_to_le16(params);
5236 pSMB->ParameterCount = pSMB->TotalParameterCount;
5237 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005238 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239
5240 pSMB->DataCount = 0;
5241 pSMB->DataOffset = 0;
5242 pSMB->SetupCount = 1;
5243 pSMB->Reserved3 = 0;
5244 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5245 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005246 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 pSMB->ByteCount = cpu_to_le16(byte_count);
5248
5249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5251 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005252 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 } else { /* decode response */
5254 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5255
Jeff Layton820a8032011-05-04 08:05:26 -04005256 if (rc || get_bcc(&pSMBr->hdr) <
5257 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 rc = -EIO; /* bad smb */
5259 else {
5260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5261 response_data =
Steve French737b7582005-04-28 22:41:06 -07005262 (FILE_SYSTEM_DEVICE_INFO *)
5263 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 data_offset);
5265 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005266 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 }
5268 }
5269 cifs_buf_release(pSMB);
5270
5271 if (rc == -EAGAIN)
5272 goto QFSDeviceRetry;
5273
5274 return rc;
5275}
5276
5277int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005278CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279{
5280/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5281 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5282 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5283 FILE_SYSTEM_UNIX_INFO *response_data;
5284 int rc = 0;
5285 int bytes_returned = 0;
5286 __u16 params, byte_count;
5287
Joe Perchesf96637b2013-05-04 22:12:25 -05005288 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005290 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5291 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 if (rc)
5293 return rc;
5294
5295 params = 2; /* level */
5296 pSMB->TotalDataCount = 0;
5297 pSMB->DataCount = 0;
5298 pSMB->DataOffset = 0;
5299 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005300 /* BB find exact max SMB PDU from sess structure BB */
5301 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 pSMB->MaxSetupCount = 0;
5303 pSMB->Reserved = 0;
5304 pSMB->Flags = 0;
5305 pSMB->Timeout = 0;
5306 pSMB->Reserved2 = 0;
5307 byte_count = params + 1 /* pad */ ;
5308 pSMB->ParameterCount = cpu_to_le16(params);
5309 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005310 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5311 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 pSMB->SetupCount = 1;
5313 pSMB->Reserved3 = 0;
5314 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5315 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005316 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 pSMB->ByteCount = cpu_to_le16(byte_count);
5318
5319 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5320 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5321 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005322 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 } else { /* decode response */
5324 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5325
Jeff Layton820a8032011-05-04 08:05:26 -04005326 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 rc = -EIO; /* bad smb */
5328 } else {
5329 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5330 response_data =
5331 (FILE_SYSTEM_UNIX_INFO
5332 *) (((char *) &pSMBr->hdr.Protocol) +
5333 data_offset);
5334 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005335 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 }
5337 }
5338 cifs_buf_release(pSMB);
5339
5340 if (rc == -EAGAIN)
5341 goto QFSUnixRetry;
5342
5343
5344 return rc;
5345}
5346
Jeremy Allisonac670552005-06-22 17:26:35 -07005347int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005348CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005349{
5350/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5351 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5352 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5353 int rc = 0;
5354 int bytes_returned = 0;
5355 __u16 params, param_offset, offset, byte_count;
5356
Joe Perchesf96637b2013-05-04 22:12:25 -05005357 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005358SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005359 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005360 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5361 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005362 if (rc)
5363 return rc;
5364
5365 params = 4; /* 2 bytes zero followed by info level. */
5366 pSMB->MaxSetupCount = 0;
5367 pSMB->Reserved = 0;
5368 pSMB->Flags = 0;
5369 pSMB->Timeout = 0;
5370 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005371 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5372 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005373 offset = param_offset + params;
5374
5375 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005376 /* BB find exact max SMB PDU from sess structure BB */
5377 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005378 pSMB->SetupCount = 1;
5379 pSMB->Reserved3 = 0;
5380 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5381 byte_count = 1 /* pad */ + params + 12;
5382
5383 pSMB->DataCount = cpu_to_le16(12);
5384 pSMB->ParameterCount = cpu_to_le16(params);
5385 pSMB->TotalDataCount = pSMB->DataCount;
5386 pSMB->TotalParameterCount = pSMB->ParameterCount;
5387 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5388 pSMB->DataOffset = cpu_to_le16(offset);
5389
5390 /* Params. */
5391 pSMB->FileNum = 0;
5392 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5393
5394 /* Data. */
5395 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5396 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5397 pSMB->ClientUnixCap = cpu_to_le64(cap);
5398
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005399 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005400 pSMB->ByteCount = cpu_to_le16(byte_count);
5401
5402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5404 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005405 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005406 } else { /* decode response */
5407 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005408 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005409 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005410 }
5411 cifs_buf_release(pSMB);
5412
5413 if (rc == -EAGAIN)
5414 goto SETFSUnixRetry;
5415
5416 return rc;
5417}
5418
5419
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420
5421int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005422CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005423 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424{
5425/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5426 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5427 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5428 FILE_SYSTEM_POSIX_INFO *response_data;
5429 int rc = 0;
5430 int bytes_returned = 0;
5431 __u16 params, byte_count;
5432
Joe Perchesf96637b2013-05-04 22:12:25 -05005433 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434QFSPosixRetry:
5435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5436 (void **) &pSMBr);
5437 if (rc)
5438 return rc;
5439
5440 params = 2; /* level */
5441 pSMB->TotalDataCount = 0;
5442 pSMB->DataCount = 0;
5443 pSMB->DataOffset = 0;
5444 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005445 /* BB find exact max SMB PDU from sess structure BB */
5446 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 pSMB->MaxSetupCount = 0;
5448 pSMB->Reserved = 0;
5449 pSMB->Flags = 0;
5450 pSMB->Timeout = 0;
5451 pSMB->Reserved2 = 0;
5452 byte_count = params + 1 /* pad */ ;
5453 pSMB->ParameterCount = cpu_to_le16(params);
5454 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005455 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5456 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 pSMB->SetupCount = 1;
5458 pSMB->Reserved3 = 0;
5459 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5460 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005461 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 pSMB->ByteCount = cpu_to_le16(byte_count);
5463
5464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5466 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005467 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 } else { /* decode response */
5469 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5470
Jeff Layton820a8032011-05-04 08:05:26 -04005471 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 rc = -EIO; /* bad smb */
5473 } else {
5474 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5475 response_data =
5476 (FILE_SYSTEM_POSIX_INFO
5477 *) (((char *) &pSMBr->hdr.Protocol) +
5478 data_offset);
5479 FSData->f_bsize =
5480 le32_to_cpu(response_data->BlockSize);
5481 FSData->f_blocks =
5482 le64_to_cpu(response_data->TotalBlocks);
5483 FSData->f_bfree =
5484 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005485 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 FSData->f_bavail = FSData->f_bfree;
5487 } else {
5488 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005489 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 }
Steve French790fe572007-07-07 19:25:05 +00005491 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005493 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005494 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005496 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 }
5498 }
5499 cifs_buf_release(pSMB);
5500
5501 if (rc == -EAGAIN)
5502 goto QFSPosixRetry;
5503
5504 return rc;
5505}
5506
5507
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005508/*
5509 * We can not use write of zero bytes trick to set file size due to need for
5510 * large file support. Also note that this SetPathInfo is preferred to
5511 * SetFileInfo based method in next routine which is only needed to work around
5512 * a sharing violation bugin Samba which this routine can run into.
5513 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005515CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005516 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5517 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518{
5519 struct smb_com_transaction2_spi_req *pSMB = NULL;
5520 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5521 struct file_end_of_file_info *parm_data;
5522 int name_len;
5523 int rc = 0;
5524 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005525 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5526
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 __u16 params, byte_count, data_count, param_offset, offset;
5528
Joe Perchesf96637b2013-05-04 22:12:25 -05005529 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530SetEOFRetry:
5531 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5532 (void **) &pSMBr);
5533 if (rc)
5534 return rc;
5535
5536 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5537 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005538 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5539 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 name_len++; /* trailing null */
5541 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005542 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005543 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005545 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 }
5547 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005548 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005550 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 pSMB->MaxSetupCount = 0;
5552 pSMB->Reserved = 0;
5553 pSMB->Flags = 0;
5554 pSMB->Timeout = 0;
5555 pSMB->Reserved2 = 0;
5556 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005557 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005559 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005560 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5561 pSMB->InformationLevel =
5562 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5563 else
5564 pSMB->InformationLevel =
5565 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5566 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5568 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005569 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 else
5571 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005572 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 }
5574
5575 parm_data =
5576 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5577 offset);
5578 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5579 pSMB->DataOffset = cpu_to_le16(offset);
5580 pSMB->SetupCount = 1;
5581 pSMB->Reserved3 = 0;
5582 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5583 byte_count = 3 /* pad */ + params + data_count;
5584 pSMB->DataCount = cpu_to_le16(data_count);
5585 pSMB->TotalDataCount = pSMB->DataCount;
5586 pSMB->ParameterCount = cpu_to_le16(params);
5587 pSMB->TotalParameterCount = pSMB->ParameterCount;
5588 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005589 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 parm_data->FileSize = cpu_to_le64(size);
5591 pSMB->ByteCount = cpu_to_le16(byte_count);
5592 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5593 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005594 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005595 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596
5597 cifs_buf_release(pSMB);
5598
5599 if (rc == -EAGAIN)
5600 goto SetEOFRetry;
5601
5602 return rc;
5603}
5604
5605int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005606CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5607 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608{
5609 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 struct file_end_of_file_info *parm_data;
5611 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 __u16 params, param_offset, offset, byte_count, count;
5613
Joe Perchesf96637b2013-05-04 22:12:25 -05005614 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5615 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005616 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5617
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 if (rc)
5619 return rc;
5620
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005621 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5622 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005623
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 params = 6;
5625 pSMB->MaxSetupCount = 0;
5626 pSMB->Reserved = 0;
5627 pSMB->Flags = 0;
5628 pSMB->Timeout = 0;
5629 pSMB->Reserved2 = 0;
5630 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5631 offset = param_offset + params;
5632
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 count = sizeof(struct file_end_of_file_info);
5634 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005635 /* BB find exact max SMB PDU from sess structure BB */
5636 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 pSMB->SetupCount = 1;
5638 pSMB->Reserved3 = 0;
5639 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5640 byte_count = 3 /* pad */ + params + count;
5641 pSMB->DataCount = cpu_to_le16(count);
5642 pSMB->ParameterCount = cpu_to_le16(params);
5643 pSMB->TotalDataCount = pSMB->DataCount;
5644 pSMB->TotalParameterCount = pSMB->ParameterCount;
5645 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5646 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005647 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5648 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 pSMB->DataOffset = cpu_to_le16(offset);
5650 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005651 pSMB->Fid = cfile->fid.netfid;
5652 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5654 pSMB->InformationLevel =
5655 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5656 else
5657 pSMB->InformationLevel =
5658 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005659 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5661 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005662 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 else
5664 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005665 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 }
5667 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005668 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005670 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005672 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5673 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 }
5675
Steve French50c2f752007-07-13 00:33:32 +00005676 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 since file handle passed in no longer valid */
5678
5679 return rc;
5680}
5681
Steve French50c2f752007-07-13 00:33:32 +00005682/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 an open handle, rather than by pathname - this is awkward due to
5684 potential access conflicts on the open, but it is unavoidable for these
5685 old servers since the only other choice is to go from 100 nanosecond DCE
5686 time and resort to the original setpathinfo level which takes the ancient
5687 DOS time format with 2 second granularity */
5688int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005689CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005690 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691{
5692 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 char *data_offset;
5694 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 __u16 params, param_offset, offset, byte_count, count;
5696
Joe Perchesf96637b2013-05-04 22:12:25 -05005697 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005698 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5699
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 if (rc)
5701 return rc;
5702
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005703 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5704 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005705
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 params = 6;
5707 pSMB->MaxSetupCount = 0;
5708 pSMB->Reserved = 0;
5709 pSMB->Flags = 0;
5710 pSMB->Timeout = 0;
5711 pSMB->Reserved2 = 0;
5712 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5713 offset = param_offset + params;
5714
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005715 data_offset = (char *)pSMB +
5716 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
Steve French26f57362007-08-30 22:09:15 +00005718 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005720 /* BB find max SMB PDU from sess */
5721 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 pSMB->SetupCount = 1;
5723 pSMB->Reserved3 = 0;
5724 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5725 byte_count = 3 /* pad */ + params + count;
5726 pSMB->DataCount = cpu_to_le16(count);
5727 pSMB->ParameterCount = cpu_to_le16(params);
5728 pSMB->TotalDataCount = pSMB->DataCount;
5729 pSMB->TotalParameterCount = pSMB->ParameterCount;
5730 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5731 pSMB->DataOffset = cpu_to_le16(offset);
5732 pSMB->Fid = fid;
5733 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5734 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5735 else
5736 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5737 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005738 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005740 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005741 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005742 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005743 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5744 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745
Steve French50c2f752007-07-13 00:33:32 +00005746 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 since file handle passed in no longer valid */
5748
5749 return rc;
5750}
5751
Jeff Layton6d22f092008-09-23 11:48:35 -04005752int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005753CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005754 bool delete_file, __u16 fid, __u32 pid_of_opener)
5755{
5756 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5757 char *data_offset;
5758 int rc = 0;
5759 __u16 params, param_offset, offset, byte_count, count;
5760
Joe Perchesf96637b2013-05-04 22:12:25 -05005761 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005762 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5763
5764 if (rc)
5765 return rc;
5766
5767 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5768 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5769
5770 params = 6;
5771 pSMB->MaxSetupCount = 0;
5772 pSMB->Reserved = 0;
5773 pSMB->Flags = 0;
5774 pSMB->Timeout = 0;
5775 pSMB->Reserved2 = 0;
5776 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5777 offset = param_offset + params;
5778
5779 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5780
5781 count = 1;
5782 pSMB->MaxParameterCount = cpu_to_le16(2);
5783 /* BB find max SMB PDU from sess */
5784 pSMB->MaxDataCount = cpu_to_le16(1000);
5785 pSMB->SetupCount = 1;
5786 pSMB->Reserved3 = 0;
5787 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5788 byte_count = 3 /* pad */ + params + count;
5789 pSMB->DataCount = cpu_to_le16(count);
5790 pSMB->ParameterCount = cpu_to_le16(params);
5791 pSMB->TotalDataCount = pSMB->DataCount;
5792 pSMB->TotalParameterCount = pSMB->ParameterCount;
5793 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5794 pSMB->DataOffset = cpu_to_le16(offset);
5795 pSMB->Fid = fid;
5796 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5797 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005798 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005799 pSMB->ByteCount = cpu_to_le16(byte_count);
5800 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005801 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005802 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005803 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005804
5805 return rc;
5806}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807
5808int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005809CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005810 const char *fileName, const FILE_BASIC_INFO *data,
5811 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812{
5813 TRANSACTION2_SPI_REQ *pSMB = NULL;
5814 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5815 int name_len;
5816 int rc = 0;
5817 int bytes_returned = 0;
5818 char *data_offset;
5819 __u16 params, param_offset, offset, byte_count, count;
5820
Joe Perchesf96637b2013-05-04 22:12:25 -05005821 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
5823SetTimesRetry:
5824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5825 (void **) &pSMBr);
5826 if (rc)
5827 return rc;
5828
5829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5830 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005831 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5832 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 name_len++; /* trailing null */
5834 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005835 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 name_len = strnlen(fileName, PATH_MAX);
5837 name_len++; /* trailing null */
5838 strncpy(pSMB->FileName, fileName, name_len);
5839 }
5840
5841 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005842 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005844 /* BB find max SMB PDU from sess structure BB */
5845 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 pSMB->MaxSetupCount = 0;
5847 pSMB->Reserved = 0;
5848 pSMB->Flags = 0;
5849 pSMB->Timeout = 0;
5850 pSMB->Reserved2 = 0;
5851 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005852 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853 offset = param_offset + params;
5854 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5855 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5856 pSMB->DataOffset = cpu_to_le16(offset);
5857 pSMB->SetupCount = 1;
5858 pSMB->Reserved3 = 0;
5859 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5860 byte_count = 3 /* pad */ + params + count;
5861
5862 pSMB->DataCount = cpu_to_le16(count);
5863 pSMB->ParameterCount = cpu_to_le16(params);
5864 pSMB->TotalDataCount = pSMB->DataCount;
5865 pSMB->TotalParameterCount = pSMB->ParameterCount;
5866 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5867 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5868 else
5869 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5870 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005871 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005872 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 pSMB->ByteCount = cpu_to_le16(byte_count);
5874 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5875 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005876 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005877 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878
5879 cifs_buf_release(pSMB);
5880
5881 if (rc == -EAGAIN)
5882 goto SetTimesRetry;
5883
5884 return rc;
5885}
5886
5887/* Can not be used to set time stamps yet (due to old DOS time format) */
5888/* Can be used to set attributes */
5889#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5890 handling it anyway and NT4 was what we thought it would be needed for
5891 Do not delete it until we prove whether needed for Win9x though */
5892int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005893CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 __u16 dos_attrs, const struct nls_table *nls_codepage)
5895{
5896 SETATTR_REQ *pSMB = NULL;
5897 SETATTR_RSP *pSMBr = NULL;
5898 int rc = 0;
5899 int bytes_returned;
5900 int name_len;
5901
Joe Perchesf96637b2013-05-04 22:12:25 -05005902 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903
5904SetAttrLgcyRetry:
5905 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5906 (void **) &pSMBr);
5907 if (rc)
5908 return rc;
5909
5910 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5911 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005912 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5913 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 name_len++; /* trailing null */
5915 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005916 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 name_len = strnlen(fileName, PATH_MAX);
5918 name_len++; /* trailing null */
5919 strncpy(pSMB->fileName, fileName, name_len);
5920 }
5921 pSMB->attr = cpu_to_le16(dos_attrs);
5922 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005923 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005927 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005928 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929
5930 cifs_buf_release(pSMB);
5931
5932 if (rc == -EAGAIN)
5933 goto SetAttrLgcyRetry;
5934
5935 return rc;
5936}
5937#endif /* temporarily unneeded SetAttr legacy function */
5938
Jeff Layton654cf142009-07-09 20:02:49 -04005939static void
5940cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5941 const struct cifs_unix_set_info_args *args)
5942{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005943 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005944 u64 mode = args->mode;
5945
Eric W. Biederman49418b22013-02-06 00:57:56 -08005946 if (uid_valid(args->uid))
5947 uid = from_kuid(&init_user_ns, args->uid);
5948 if (gid_valid(args->gid))
5949 gid = from_kgid(&init_user_ns, args->gid);
5950
Jeff Layton654cf142009-07-09 20:02:49 -04005951 /*
5952 * Samba server ignores set of file size to zero due to bugs in some
5953 * older clients, but we should be precise - we use SetFileSize to
5954 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005955 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005956 * zero instead of -1 here
5957 */
5958 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5959 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5960 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5961 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5962 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005963 data_offset->Uid = cpu_to_le64(uid);
5964 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005965 /* better to leave device as zero when it is */
5966 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5967 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5968 data_offset->Permissions = cpu_to_le64(mode);
5969
5970 if (S_ISREG(mode))
5971 data_offset->Type = cpu_to_le32(UNIX_FILE);
5972 else if (S_ISDIR(mode))
5973 data_offset->Type = cpu_to_le32(UNIX_DIR);
5974 else if (S_ISLNK(mode))
5975 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5976 else if (S_ISCHR(mode))
5977 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5978 else if (S_ISBLK(mode))
5979 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5980 else if (S_ISFIFO(mode))
5981 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5982 else if (S_ISSOCK(mode))
5983 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5984}
5985
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005987CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005988 const struct cifs_unix_set_info_args *args,
5989 u16 fid, u32 pid_of_opener)
5990{
5991 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005992 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005993 int rc = 0;
5994 u16 params, param_offset, offset, byte_count, count;
5995
Joe Perchesf96637b2013-05-04 22:12:25 -05005996 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005997 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5998
5999 if (rc)
6000 return rc;
6001
6002 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6003 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6004
6005 params = 6;
6006 pSMB->MaxSetupCount = 0;
6007 pSMB->Reserved = 0;
6008 pSMB->Flags = 0;
6009 pSMB->Timeout = 0;
6010 pSMB->Reserved2 = 0;
6011 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6012 offset = param_offset + params;
6013
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006014 data_offset = (char *)pSMB +
6015 offsetof(struct smb_hdr, Protocol) + offset;
6016
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006017 count = sizeof(FILE_UNIX_BASIC_INFO);
6018
6019 pSMB->MaxParameterCount = cpu_to_le16(2);
6020 /* BB find max SMB PDU from sess */
6021 pSMB->MaxDataCount = cpu_to_le16(1000);
6022 pSMB->SetupCount = 1;
6023 pSMB->Reserved3 = 0;
6024 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6025 byte_count = 3 /* pad */ + params + count;
6026 pSMB->DataCount = cpu_to_le16(count);
6027 pSMB->ParameterCount = cpu_to_le16(params);
6028 pSMB->TotalDataCount = pSMB->DataCount;
6029 pSMB->TotalParameterCount = pSMB->ParameterCount;
6030 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6031 pSMB->DataOffset = cpu_to_le16(offset);
6032 pSMB->Fid = fid;
6033 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6034 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006035 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006036 pSMB->ByteCount = cpu_to_le16(byte_count);
6037
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006038 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006039
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006040 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006041 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006042 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6043 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006044
6045 /* Note: On -EAGAIN error only caller can retry on handle based calls
6046 since file handle passed in no longer valid */
6047
6048 return rc;
6049}
6050
6051int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006052CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006053 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006054 const struct cifs_unix_set_info_args *args,
6055 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056{
6057 TRANSACTION2_SPI_REQ *pSMB = NULL;
6058 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6059 int name_len;
6060 int rc = 0;
6061 int bytes_returned = 0;
6062 FILE_UNIX_BASIC_INFO *data_offset;
6063 __u16 params, param_offset, offset, count, byte_count;
6064
Joe Perchesf96637b2013-05-04 22:12:25 -05006065 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066setPermsRetry:
6067 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6068 (void **) &pSMBr);
6069 if (rc)
6070 return rc;
6071
6072 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6073 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006074 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006075 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 name_len++; /* trailing null */
6077 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006078 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006079 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006081 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 }
6083
6084 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006085 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006087 /* BB find max SMB PDU from sess structure BB */
6088 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 pSMB->MaxSetupCount = 0;
6090 pSMB->Reserved = 0;
6091 pSMB->Flags = 0;
6092 pSMB->Timeout = 0;
6093 pSMB->Reserved2 = 0;
6094 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006095 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 offset = param_offset + params;
6097 data_offset =
6098 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6099 offset);
6100 memset(data_offset, 0, count);
6101 pSMB->DataOffset = cpu_to_le16(offset);
6102 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6103 pSMB->SetupCount = 1;
6104 pSMB->Reserved3 = 0;
6105 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6106 byte_count = 3 /* pad */ + params + count;
6107 pSMB->ParameterCount = cpu_to_le16(params);
6108 pSMB->DataCount = cpu_to_le16(count);
6109 pSMB->TotalParameterCount = pSMB->ParameterCount;
6110 pSMB->TotalDataCount = pSMB->DataCount;
6111 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6112 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006113 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006114
Jeff Layton654cf142009-07-09 20:02:49 -04006115 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116
6117 pSMB->ByteCount = cpu_to_le16(byte_count);
6118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006120 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006121 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122
Steve French0d817bc2008-05-22 02:02:03 +00006123 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 if (rc == -EAGAIN)
6125 goto setPermsRetry;
6126 return rc;
6127}
6128
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006130/*
6131 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6132 * function used by listxattr and getxattr type calls. When ea_name is set,
6133 * it looks for that attribute name and stuffs that value into the EAData
6134 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6135 * buffer. In both cases, the return value is either the length of the
6136 * resulting data or a negative error code. If EAData is a NULL pointer then
6137 * the data isn't copied to it, but the length is returned.
6138 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006140CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006141 const unsigned char *searchName, const unsigned char *ea_name,
6142 char *EAData, size_t buf_size,
6143 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144{
6145 /* BB assumes one setup word */
6146 TRANSACTION2_QPI_REQ *pSMB = NULL;
6147 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6148 int rc = 0;
6149 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006150 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006151 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006152 struct fea *temp_fea;
6153 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006154 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006155 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006156 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157
Joe Perchesf96637b2013-05-04 22:12:25 -05006158 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159QAllEAsRetry:
6160 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6161 (void **) &pSMBr);
6162 if (rc)
6163 return rc;
6164
6165 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006166 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006167 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6168 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006169 list_len++; /* trailing null */
6170 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006172 list_len = strnlen(searchName, PATH_MAX);
6173 list_len++; /* trailing null */
6174 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175 }
6176
Jeff Layton6e462b92010-02-10 16:18:26 -05006177 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178 pSMB->TotalDataCount = 0;
6179 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006180 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006181 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182 pSMB->MaxSetupCount = 0;
6183 pSMB->Reserved = 0;
6184 pSMB->Flags = 0;
6185 pSMB->Timeout = 0;
6186 pSMB->Reserved2 = 0;
6187 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006188 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189 pSMB->DataCount = 0;
6190 pSMB->DataOffset = 0;
6191 pSMB->SetupCount = 1;
6192 pSMB->Reserved3 = 0;
6193 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6194 byte_count = params + 1 /* pad */ ;
6195 pSMB->TotalParameterCount = cpu_to_le16(params);
6196 pSMB->ParameterCount = pSMB->TotalParameterCount;
6197 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6198 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006199 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 pSMB->ByteCount = cpu_to_le16(byte_count);
6201
6202 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6203 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6204 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006205 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006206 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006208
6209
6210 /* BB also check enough total bytes returned */
6211 /* BB we need to improve the validity checking
6212 of these trans2 responses */
6213
6214 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006215 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006216 rc = -EIO; /* bad smb */
6217 goto QAllEAsOut;
6218 }
6219
6220 /* check that length of list is not more than bcc */
6221 /* check that each entry does not go beyond length
6222 of list */
6223 /* check that each element of each entry does not
6224 go beyond end of list */
6225 /* validate_trans2_offsets() */
6226 /* BB check if start of smb + data_offset > &bcc+ bcc */
6227
6228 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6229 ea_response_data = (struct fealist *)
6230 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6231
Jeff Layton6e462b92010-02-10 16:18:26 -05006232 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006233 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006234 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006235 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006236 /* didn't find the named attribute */
6237 if (ea_name)
6238 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006239 goto QAllEAsOut;
6240 }
6241
Jeff Layton0cd126b2010-02-10 16:18:26 -05006242 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006243 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006244 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006245 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006246 rc = -EIO;
6247 goto QAllEAsOut;
6248 }
6249
Jeff Laytonf0d38682010-02-10 16:18:26 -05006250 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006251 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006252 temp_fea = ea_response_data->list;
6253 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006254 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006255 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006256 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006257
Jeff Layton6e462b92010-02-10 16:18:26 -05006258 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006259 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006260 /* make sure we can read name_len and value_len */
6261 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006262 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006263 rc = -EIO;
6264 goto QAllEAsOut;
6265 }
6266
6267 name_len = temp_fea->name_len;
6268 value_len = le16_to_cpu(temp_fea->value_len);
6269 list_len -= name_len + 1 + value_len;
6270 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006271 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006272 rc = -EIO;
6273 goto QAllEAsOut;
6274 }
6275
Jeff Layton31c05192010-02-10 16:18:26 -05006276 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006277 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006278 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006279 temp_ptr += name_len + 1;
6280 rc = value_len;
6281 if (buf_size == 0)
6282 goto QAllEAsOut;
6283 if ((size_t)value_len > buf_size) {
6284 rc = -ERANGE;
6285 goto QAllEAsOut;
6286 }
6287 memcpy(EAData, temp_ptr, value_len);
6288 goto QAllEAsOut;
6289 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006290 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006291 /* account for prefix user. and trailing null */
6292 rc += (5 + 1 + name_len);
6293 if (rc < (int) buf_size) {
6294 memcpy(EAData, "user.", 5);
6295 EAData += 5;
6296 memcpy(EAData, temp_ptr, name_len);
6297 EAData += name_len;
6298 /* null terminate name */
6299 *EAData = 0;
6300 ++EAData;
6301 } else if (buf_size == 0) {
6302 /* skip copy - calc size only */
6303 } else {
6304 /* stop before overrun buffer */
6305 rc = -ERANGE;
6306 break;
6307 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006308 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006309 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006310 temp_fea = (struct fea *)temp_ptr;
6311 }
6312
Jeff Layton31c05192010-02-10 16:18:26 -05006313 /* didn't find the named attribute */
6314 if (ea_name)
6315 rc = -ENODATA;
6316
Jeff Laytonf0d38682010-02-10 16:18:26 -05006317QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006318 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 if (rc == -EAGAIN)
6320 goto QAllEAsRetry;
6321
6322 return (ssize_t)rc;
6323}
6324
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006326CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6327 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006328 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6329 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330{
6331 struct smb_com_transaction2_spi_req *pSMB = NULL;
6332 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6333 struct fealist *parm_data;
6334 int name_len;
6335 int rc = 0;
6336 int bytes_returned = 0;
6337 __u16 params, param_offset, byte_count, offset, count;
6338
Joe Perchesf96637b2013-05-04 22:12:25 -05006339 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340SetEARetry:
6341 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6342 (void **) &pSMBr);
6343 if (rc)
6344 return rc;
6345
6346 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6347 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006348 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6349 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 name_len++; /* trailing null */
6351 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006352 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353 name_len = strnlen(fileName, PATH_MAX);
6354 name_len++; /* trailing null */
6355 strncpy(pSMB->FileName, fileName, name_len);
6356 }
6357
6358 params = 6 + name_len;
6359
6360 /* done calculating parms using name_len of file name,
6361 now use name_len to calculate length of ea name
6362 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006363 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 name_len = 0;
6365 else
Steve French50c2f752007-07-13 00:33:32 +00006366 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006368 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006370 /* BB find max SMB PDU from sess */
6371 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 pSMB->MaxSetupCount = 0;
6373 pSMB->Reserved = 0;
6374 pSMB->Flags = 0;
6375 pSMB->Timeout = 0;
6376 pSMB->Reserved2 = 0;
6377 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006378 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 offset = param_offset + params;
6380 pSMB->InformationLevel =
6381 cpu_to_le16(SMB_SET_FILE_EA);
6382
6383 parm_data =
6384 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6385 offset);
6386 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6387 pSMB->DataOffset = cpu_to_le16(offset);
6388 pSMB->SetupCount = 1;
6389 pSMB->Reserved3 = 0;
6390 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6391 byte_count = 3 /* pad */ + params + count;
6392 pSMB->DataCount = cpu_to_le16(count);
6393 parm_data->list_len = cpu_to_le32(count);
6394 parm_data->list[0].EA_flags = 0;
6395 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006396 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006398 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006399 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400 parm_data->list[0].name[name_len] = 0;
6401 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6402 /* caller ensures that ea_value_len is less than 64K but
6403 we need to ensure that it fits within the smb */
6404
Steve French50c2f752007-07-13 00:33:32 +00006405 /*BB add length check to see if it would fit in
6406 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006407 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6408 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006409 memcpy(parm_data->list[0].name+name_len+1,
6410 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411
6412 pSMB->TotalDataCount = pSMB->DataCount;
6413 pSMB->ParameterCount = cpu_to_le16(params);
6414 pSMB->TotalParameterCount = pSMB->ParameterCount;
6415 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006416 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006417 pSMB->ByteCount = cpu_to_le16(byte_count);
6418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006420 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006421 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422
6423 cifs_buf_release(pSMB);
6424
6425 if (rc == -EAGAIN)
6426 goto SetEARetry;
6427
6428 return rc;
6429}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006430#endif
Steve French0eff0e22011-02-24 05:39:23 +00006431
6432#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6433/*
6434 * Years ago the kernel added a "dnotify" function for Samba server,
6435 * to allow network clients (such as Windows) to display updated
6436 * lists of files in directory listings automatically when
6437 * files are added by one user when another user has the
6438 * same directory open on their desktop. The Linux cifs kernel
6439 * client hooked into the kernel side of this interface for
6440 * the same reason, but ironically when the VFS moved from
6441 * "dnotify" to "inotify" it became harder to plug in Linux
6442 * network file system clients (the most obvious use case
6443 * for notify interfaces is when multiple users can update
6444 * the contents of the same directory - exactly what network
6445 * file systems can do) although the server (Samba) could
6446 * still use it. For the short term we leave the worker
6447 * function ifdeffed out (below) until inotify is fixed
6448 * in the VFS to make it easier to plug in network file
6449 * system clients. If inotify turns out to be permanently
6450 * incompatible for network fs clients, we could instead simply
6451 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6452 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006453int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006454 const int notify_subdirs, const __u16 netfid,
6455 __u32 filter, struct file *pfile, int multishot,
6456 const struct nls_table *nls_codepage)
6457{
6458 int rc = 0;
6459 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6460 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6461 struct dir_notify_req *dnotify_req;
6462 int bytes_returned;
6463
Joe Perchesf96637b2013-05-04 22:12:25 -05006464 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006465 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6466 (void **) &pSMBr);
6467 if (rc)
6468 return rc;
6469
6470 pSMB->TotalParameterCount = 0 ;
6471 pSMB->TotalDataCount = 0;
6472 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006473 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006474 pSMB->MaxSetupCount = 4;
6475 pSMB->Reserved = 0;
6476 pSMB->ParameterOffset = 0;
6477 pSMB->DataCount = 0;
6478 pSMB->DataOffset = 0;
6479 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6480 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6481 pSMB->ParameterCount = pSMB->TotalParameterCount;
6482 if (notify_subdirs)
6483 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6484 pSMB->Reserved2 = 0;
6485 pSMB->CompletionFilter = cpu_to_le32(filter);
6486 pSMB->Fid = netfid; /* file handle always le */
6487 pSMB->ByteCount = 0;
6488
6489 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6490 (struct smb_hdr *)pSMBr, &bytes_returned,
6491 CIFS_ASYNC_OP);
6492 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006493 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006494 } else {
6495 /* Add file to outstanding requests */
6496 /* BB change to kmem cache alloc */
6497 dnotify_req = kmalloc(
6498 sizeof(struct dir_notify_req),
6499 GFP_KERNEL);
6500 if (dnotify_req) {
6501 dnotify_req->Pid = pSMB->hdr.Pid;
6502 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6503 dnotify_req->Mid = pSMB->hdr.Mid;
6504 dnotify_req->Tid = pSMB->hdr.Tid;
6505 dnotify_req->Uid = pSMB->hdr.Uid;
6506 dnotify_req->netfid = netfid;
6507 dnotify_req->pfile = pfile;
6508 dnotify_req->filter = filter;
6509 dnotify_req->multishot = multishot;
6510 spin_lock(&GlobalMid_Lock);
6511 list_add_tail(&dnotify_req->lhead,
6512 &GlobalDnotifyReqList);
6513 spin_unlock(&GlobalMid_Lock);
6514 } else
6515 rc = -ENOMEM;
6516 }
6517 cifs_buf_release(pSMB);
6518 return rc;
6519}
6520#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */