blob: 9b4aea85b15c247ecebf9d0a74b11d1a689e55c6 [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
199 /*
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
202 */
203 atomic_inc(&tconInfoReconnectCount);
204
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208
209 /*
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
212 *
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 */
215
216out:
217 /*
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
220 */
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
228 }
229
230 unload_nls(nls_codepage);
231 return rc;
232}
233
Steve Frenchad7a2922008-02-07 23:25:02 +0000234/* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int
Steve French96daf2b2011-05-27 04:34:02 +0000238small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000239 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Jeff Laytonf5695992010-09-29 15:27:08 -0400241 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000244 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return rc;
246
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
251 }
252
Steve French63135e02007-07-17 17:34:02 +0000253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000254 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Steve French790fe572007-07-07 19:25:05 +0000256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700258
Jeff Laytonf5695992010-09-29 15:27:08 -0400259 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000260}
261
Steve French12b3b8f2006-02-09 21:12:47 +0000262int
Steve French50c2f752007-07-13 00:33:32 +0000263small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000264 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000265{
266 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000267 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000268
Steve French5815449d2006-02-14 01:36:20 +0000269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 return rc;
272
Steve French04fdabe2006-02-10 05:52:50 +0000273 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400274 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000277 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279
280 /* uid, tid can stay at zero as set in header assemble */
281
Steve French50c2f752007-07-13 00:33:32 +0000282 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000283 this function is used after 1st of session setup requests */
284
285 return rc;
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288/* If the return code is zero, this function must fill in request_buf pointer */
289static int
Steve French96daf2b2011-05-27 04:34:02 +0000290__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400291 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700310
Jeff Laytonf5695992010-09-29 15:27:08 -0400311 return 0;
312}
313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
318{
319 int rc;
320
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
324
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326}
327
328static int
Steve French96daf2b2011-05-27 04:34:02 +0000329smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400330 void **request_buf, void **response_buf)
331{
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
334
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Steve French50c2f752007-07-13 00:33:32 +0000338static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
354
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
357 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
362
363 return 0;
364vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Jeff Layton690c5222011-01-20 13:36:51 -0500369
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400370static int
371decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
372{
373 int rc = 0;
374 u16 count;
375 char *guid = pSMBr->u.extended_response.GUID;
376
377 count = get_bcc(&pSMBr->hdr);
378 if (count < SMB1_CLIENT_GUID_SIZE)
379 return -EIO;
380
381 spin_lock(&cifs_tcp_ses_lock);
382 if (server->srv_count > 1) {
383 spin_unlock(&cifs_tcp_ses_lock);
384 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
385 cifs_dbg(FYI, "server UID changed\n");
386 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
387 }
388 } else {
389 spin_unlock(&cifs_tcp_ses_lock);
390 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
391 }
392
393 if (count == SMB1_CLIENT_GUID_SIZE) {
394 server->secType = RawNTLMSSP;
395 } else {
396 count -= SMB1_CLIENT_GUID_SIZE;
397 rc = decode_negTokenInit(
398 pSMBr->u.extended_response.SecurityBlob, count, server);
399 if (rc != 1)
400 return -EINVAL;
401
402 /* Make sure server supports what we want to use */
403 switch(server->secType) {
404 case Kerberos:
405 if (!server->sec_kerberos && !server->sec_mskerberos)
406 return -EOPNOTSUPP;
407 break;
408 case RawNTLMSSP:
409 if (!server->sec_ntlmssp)
410 return -EOPNOTSUPP;
411 break;
412 default:
413 return -EOPNOTSUPP;
414 }
415 }
416
417 return 0;
418}
419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400421CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
423 NEGOTIATE_REQ *pSMB;
424 NEGOTIATE_RSP *pSMBr;
425 int rc = 0;
426 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000427 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400428 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000430 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Jeff Layton3534b852013-05-24 07:41:01 -0400432 if (!server) {
433 WARN(1, "%s: server is NULL!\n", __func__);
434 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
Jeff Layton3534b852013-05-24 07:41:01 -0400436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
438 (void **) &pSMB, (void **) &pSMBr);
439 if (rc)
440 return rc;
Steve French750d1152006-06-27 06:28:30 +0000441
442 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000443 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000444 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000445 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400446 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000447
Joe Perchesf96637b2013-05-04 22:12:25 -0500448 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000449
Pavel Shilovsky88257362012-05-23 14:01:59 +0400450 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000451 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000452
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000453 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000454 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000455 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500456 cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
Steve Frencha0136892007-10-04 20:05:09 +0000457 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500458 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000459 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
460 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500461 cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000462 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
463 }
Steve French50c2f752007-07-13 00:33:32 +0000464
Steve French39798772006-05-31 22:40:51 +0000465 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000466 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000467 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
468 count += strlen(protocols[i].name) + 1;
469 /* null at end of source and target buffers anyway */
470 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000471 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 pSMB->ByteCount = cpu_to_le16(count);
473
474 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
475 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000476 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000477 goto neg_err_exit;
478
Jeff Layton9bf67e52010-04-24 07:57:46 -0400479 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500480 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000481 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400482 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000483 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000484 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000485 could not negotiate a common dialect */
486 rc = -EOPNOTSUPP;
487 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000488#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000489 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400490 && ((server->dialect == LANMAN_PROT)
491 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000492 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000493 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000494
Steve French790fe572007-07-07 19:25:05 +0000495 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000496 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000497 server->secType = LANMAN;
498 else {
Joe Perchesf96637b2013-05-04 22:12:25 -0500499 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
Steve French39798772006-05-31 22:40:51 +0000500 rc = -EOPNOTSUPP;
501 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000502 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400503 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300504 server->maxReq = min_t(unsigned int,
505 le16_to_cpu(rsp->MaxMpxCount),
506 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400507 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400508 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000509 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000510 /* even though we do not use raw we might as well set this
511 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000512 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000513 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000514 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
515 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000516 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000517 server->capabilities = CAP_MPX_MODE;
518 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000519 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000520 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000521 /* OS/2 often does not set timezone therefore
522 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000523 * Could deviate slightly from the right zone.
524 * Smallest defined timezone difference is 15 minutes
525 * (i.e. Nepal). Rounding up/down is done to match
526 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000527 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000528 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000529 struct timespec ts, utc;
530 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400531 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
532 rsp->SrvTime.Time, 0);
Joe Perchesf96637b2013-05-04 22:12:25 -0500533 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
534 (int)ts.tv_sec, (int)utc.tv_sec,
535 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000536 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000537 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000538 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000539 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000540 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000541 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000542 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000543 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000544 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000545 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000546 server->timeAdj = (int)tmp;
547 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000548 }
Joe Perchesf96637b2013-05-04 22:12:25 -0500549 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000550
Steve French39798772006-05-31 22:40:51 +0000551
Steve French254e55e2006-06-04 05:53:15 +0000552 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000553 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000554
Steve French50c2f752007-07-13 00:33:32 +0000555 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000556 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500557 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000558 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000559 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000560 rc = -EIO; /* need cryptkey unless plain text */
561 goto neg_err_exit;
562 }
Steve French39798772006-05-31 22:40:51 +0000563
Joe Perchesf96637b2013-05-04 22:12:25 -0500564 cifs_dbg(FYI, "LANMAN negotiated\n");
Steve French254e55e2006-06-04 05:53:15 +0000565 /* we will not end up setting signing flags - as no signing
566 was in LANMAN and server did not return the flags on */
567 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000568#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000569 } else if (pSMBr->hdr.WordCount == 13) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500570 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300571 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000572#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000573 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000574 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000575 /* unknown wct */
576 rc = -EOPNOTSUPP;
577 goto neg_err_exit;
578 }
579 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000580 server->sec_mode = pSMBr->SecurityMode;
581 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500582 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000583
Steve French96daf2b2011-05-27 04:34:02 +0000584 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000585#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000586 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000587#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500588 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000589
Steve French790fe572007-07-07 19:25:05 +0000590 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000591 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000592 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000593 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000594 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000595 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000596 else if (secFlags & CIFSSEC_MAY_KRB5)
597 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000598 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000599 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000600 else if (secFlags & CIFSSEC_MAY_LANMAN)
601 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000602 else {
603 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500604 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000605 goto neg_err_exit;
606 }
607 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000608
Steve French254e55e2006-06-04 05:53:15 +0000609 /* one byte, so no need to convert this or EncryptionKeyLen from
610 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300611 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
612 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400613 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000614 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400615 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000616 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500617 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000618 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000619 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
620 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400621
622 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE)
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500623 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000624 CIFS_CRYPTO_KEY_SIZE);
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400625 else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000626 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400627 (pSMBr->EncryptionKeyLength == 0))
628 rc = decode_ext_sec_blob(server, pSMBr);
629 else if (server->sec_mode & SECMODE_PW_ENCRYPT)
Steve French07cc6cf2011-05-27 04:12:29 +0000630 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400631 else
Steve French254e55e2006-06-04 05:53:15 +0000632 server->capabilities &= ~CAP_EXTENDED_SECURITY;
633
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400634 if (rc)
635 goto neg_err_exit;
636
Steve French6344a422006-06-12 04:18:35 +0000637#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000638signing_check:
Steve French6344a422006-06-12 04:18:35 +0000639#endif
Steve French762e5ab2007-06-28 18:41:42 +0000640 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
641 /* MUST_SIGN already includes the MAY_SIGN FLAG
642 so if this is zero it means that signing is disabled */
Joe Perchesf96637b2013-05-04 22:12:25 -0500643 cifs_dbg(FYI, "Signing disabled\n");
Steve French96daf2b2011-05-27 04:34:02 +0000644 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500645 cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
Steve Frenchabb63d62007-10-18 02:58:40 +0000646 rc = -EOPNOTSUPP;
647 }
Steve French96daf2b2011-05-27 04:34:02 +0000648 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000649 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000650 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
651 /* signing required */
Joe Perchesf96637b2013-05-04 22:12:25 -0500652 cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000653 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000654 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500655 cifs_dbg(VFS, "signing required but server lacks support\n");
Jeff38c10a12007-07-06 21:10:07 +0000656 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000657 } else
Steve French96daf2b2011-05-27 04:34:02 +0000658 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000659 } else {
660 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000661 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
662 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000663 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
Steve French50c2f752007-07-13 00:33:32 +0000665
666neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700667 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000668
Joe Perchesf96637b2013-05-04 22:12:25 -0500669 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 return rc;
671}
672
673int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400674CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Joe Perchesf96637b2013-05-04 22:12:25 -0500679 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500680
681 /* BB: do we need to check this? These should never be NULL. */
682 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
683 return -EIO;
684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500686 * No need to return error on this operation if tid invalidated and
687 * closed on server already e.g. due to tcp session crashing. Also,
688 * the tcon is no longer on the list, so no need to take lock before
689 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 */
Steve French268875b2009-06-25 00:29:21 +0000691 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000692 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Steve French50c2f752007-07-13 00:33:32 +0000694 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700695 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500696 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return rc;
Steve French133672e2007-11-13 22:41:37 +0000698
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400699 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500701 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Steve French50c2f752007-07-13 00:33:32 +0000703 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500704 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 if (rc == -EAGAIN)
706 rc = 0;
707
708 return rc;
709}
710
Jeff Layton766fdbb2011-01-11 07:24:21 -0500711/*
712 * This is a no-op for now. We're not really interested in the reply, but
713 * rather in the fact that the server sent one and that server->lstrp
714 * gets updated.
715 *
716 * FIXME: maybe we should consider checking that the reply matches request?
717 */
718static void
719cifs_echo_callback(struct mid_q_entry *mid)
720{
721 struct TCP_Server_Info *server = mid->callback_data;
722
723 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400724 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725}
726
727int
728CIFSSMBEcho(struct TCP_Server_Info *server)
729{
730 ECHO_REQ *smb;
731 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400732 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700733 struct smb_rqst rqst = { .rq_iov = &iov,
734 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500735
Joe Perchesf96637b2013-05-04 22:12:25 -0500736 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737
738 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
739 if (rc)
740 return rc;
741
742 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000743 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500744 smb->hdr.WordCount = 1;
745 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400746 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500747 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000748 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400749 iov.iov_base = smb;
750 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500751
Jeff Laytonfec344e2012-09-18 16:20:35 -0700752 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400753 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500754 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500755 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500756
757 cifs_small_buf_release(smb);
758
759 return rc;
760}
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400763CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 LOGOFF_ANDX_REQ *pSMB;
766 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Joe Perchesf96637b2013-05-04 22:12:25 -0500768 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500769
770 /*
771 * BB: do we need to check validity of ses and server? They should
772 * always be valid since we have an active reference. If not, that
773 * should probably be a BUG()
774 */
775 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return -EIO;
777
Steve Frenchd7b619c2010-02-25 05:36:46 +0000778 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000779 if (ses->need_reconnect)
780 goto session_already_dead; /* no need to send SMBlogoff if uid
781 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
783 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000784 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return rc;
786 }
787
Pavel Shilovsky88257362012-05-23 14:01:59 +0400788 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700789
Steve French96daf2b2011-05-27 04:34:02 +0000790 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
792 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 pSMB->hdr.Uid = ses->Suid;
795
796 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400797 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000798session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000799 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000802 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 error */
804 if (rc == -EAGAIN)
805 rc = 0;
806 return rc;
807}
808
809int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400810CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
811 const char *fileName, __u16 type,
812 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000813{
814 TRANSACTION2_SPI_REQ *pSMB = NULL;
815 TRANSACTION2_SPI_RSP *pSMBr = NULL;
816 struct unlink_psx_rq *pRqD;
817 int name_len;
818 int rc = 0;
819 int bytes_returned = 0;
820 __u16 params, param_offset, offset, byte_count;
821
Joe Perchesf96637b2013-05-04 22:12:25 -0500822 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000823PsxDelete:
824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
825 (void **) &pSMBr);
826 if (rc)
827 return rc;
828
829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
830 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600831 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
832 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000833 name_len++; /* trailing null */
834 name_len *= 2;
835 } else { /* BB add path length overrun check */
836 name_len = strnlen(fileName, PATH_MAX);
837 name_len++; /* trailing null */
838 strncpy(pSMB->FileName, fileName, name_len);
839 }
840
841 params = 6 + name_len;
842 pSMB->MaxParameterCount = cpu_to_le16(2);
843 pSMB->MaxDataCount = 0; /* BB double check this with jra */
844 pSMB->MaxSetupCount = 0;
845 pSMB->Reserved = 0;
846 pSMB->Flags = 0;
847 pSMB->Timeout = 0;
848 pSMB->Reserved2 = 0;
849 param_offset = offsetof(struct smb_com_transaction2_spi_req,
850 InformationLevel) - 4;
851 offset = param_offset + params;
852
853 /* Setup pointer to Request Data (inode type) */
854 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
855 pRqD->type = cpu_to_le16(type);
856 pSMB->ParameterOffset = cpu_to_le16(param_offset);
857 pSMB->DataOffset = cpu_to_le16(offset);
858 pSMB->SetupCount = 1;
859 pSMB->Reserved3 = 0;
860 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
861 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
862
863 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
864 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
865 pSMB->ParameterCount = cpu_to_le16(params);
866 pSMB->TotalParameterCount = pSMB->ParameterCount;
867 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
868 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000869 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000870 pSMB->ByteCount = cpu_to_le16(byte_count);
871 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
872 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000873 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500874 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000875 cifs_buf_release(pSMB);
876
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400877 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000878
879 if (rc == -EAGAIN)
880 goto PsxDelete;
881
882 return rc;
883}
884
885int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700886CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
887 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
889 DELETE_FILE_REQ *pSMB = NULL;
890 DELETE_FILE_RSP *pSMBr = NULL;
891 int rc = 0;
892 int bytes_returned;
893 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700894 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896DelFileRetry:
897 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
898 (void **) &pSMBr);
899 if (rc)
900 return rc;
901
902 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700903 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
904 PATH_MAX, cifs_sb->local_nls,
905 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 name_len++; /* trailing null */
907 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700908 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700909 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700911 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 }
913 pSMB->SearchAttributes =
914 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
915 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000916 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 pSMB->ByteCount = cpu_to_le16(name_len + 1);
918 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
919 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400920 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000921 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500922 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 cifs_buf_release(pSMB);
925 if (rc == -EAGAIN)
926 goto DelFileRetry;
927
928 return rc;
929}
930
931int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400932CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
933 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
935 DELETE_DIRECTORY_REQ *pSMB = NULL;
936 DELETE_DIRECTORY_RSP *pSMBr = NULL;
937 int rc = 0;
938 int bytes_returned;
939 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400940 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Joe Perchesf96637b2013-05-04 22:12:25 -0500942 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943RmDirRetry:
944 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
945 (void **) &pSMBr);
946 if (rc)
947 return rc;
948
949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400950 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
951 PATH_MAX, cifs_sb->local_nls,
952 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 name_len++; /* trailing null */
954 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700955 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400956 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400958 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
960
961 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000962 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 pSMB->ByteCount = cpu_to_le16(name_len + 1);
964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400966 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000967 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500968 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 cifs_buf_release(pSMB);
971 if (rc == -EAGAIN)
972 goto RmDirRetry;
973 return rc;
974}
975
976int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300977CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
978 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
980 int rc = 0;
981 CREATE_DIRECTORY_REQ *pSMB = NULL;
982 CREATE_DIRECTORY_RSP *pSMBr = NULL;
983 int bytes_returned;
984 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300985 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Joe Perchesf96637b2013-05-04 22:12:25 -0500987 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988MkDirRetry:
989 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
990 (void **) &pSMBr);
991 if (rc)
992 return rc;
993
994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600995 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300996 PATH_MAX, cifs_sb->local_nls,
997 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 name_len++; /* trailing null */
999 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001000 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 name_len = strnlen(name, PATH_MAX);
1002 name_len++; /* trailing null */
1003 strncpy(pSMB->DirName, name, name_len);
1004 }
1005
1006 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001007 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001011 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001012 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001013 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001014
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 cifs_buf_release(pSMB);
1016 if (rc == -EAGAIN)
1017 goto MkDirRetry;
1018 return rc;
1019}
1020
Steve French2dd29d32007-04-23 22:07:35 +00001021int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001022CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1023 __u32 posix_flags, __u64 mode, __u16 *netfid,
1024 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1025 const char *name, const struct nls_table *nls_codepage,
1026 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001027{
1028 TRANSACTION2_SPI_REQ *pSMB = NULL;
1029 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1030 int name_len;
1031 int rc = 0;
1032 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001033 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001034 OPEN_PSX_REQ *pdata;
1035 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001036
Joe Perchesf96637b2013-05-04 22:12:25 -05001037 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001038PsxCreat:
1039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1040 (void **) &pSMBr);
1041 if (rc)
1042 return rc;
1043
1044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1045 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001046 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1047 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001048 name_len++; /* trailing null */
1049 name_len *= 2;
1050 } else { /* BB improve the check for buffer overruns BB */
1051 name_len = strnlen(name, PATH_MAX);
1052 name_len++; /* trailing null */
1053 strncpy(pSMB->FileName, name, name_len);
1054 }
1055
1056 params = 6 + name_len;
1057 count = sizeof(OPEN_PSX_REQ);
1058 pSMB->MaxParameterCount = cpu_to_le16(2);
1059 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1060 pSMB->MaxSetupCount = 0;
1061 pSMB->Reserved = 0;
1062 pSMB->Flags = 0;
1063 pSMB->Timeout = 0;
1064 pSMB->Reserved2 = 0;
1065 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001066 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001067 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001068 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001069 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001070 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001071 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001072 pdata->OpenFlags = cpu_to_le32(*pOplock);
1073 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1074 pSMB->DataOffset = cpu_to_le16(offset);
1075 pSMB->SetupCount = 1;
1076 pSMB->Reserved3 = 0;
1077 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1078 byte_count = 3 /* pad */ + params + count;
1079
1080 pSMB->DataCount = cpu_to_le16(count);
1081 pSMB->ParameterCount = cpu_to_le16(params);
1082 pSMB->TotalDataCount = pSMB->DataCount;
1083 pSMB->TotalParameterCount = pSMB->ParameterCount;
1084 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1085 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001086 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001087 pSMB->ByteCount = cpu_to_le16(byte_count);
1088 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1090 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001091 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001092 goto psx_create_err;
1093 }
1094
Joe Perchesf96637b2013-05-04 22:12:25 -05001095 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001096 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1097
Jeff Layton820a8032011-05-04 08:05:26 -04001098 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001099 rc = -EIO; /* bad smb */
1100 goto psx_create_err;
1101 }
1102
1103 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001104 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001105 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001106
Steve French2dd29d32007-04-23 22:07:35 +00001107 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001108 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001109 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1110 /* Let caller know file was created so we can set the mode. */
1111 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001112 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001113 *pOplock |= CIFS_CREATE_ACTION;
1114 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001115 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1116 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001117 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001118 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001119 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001120 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001121 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001122 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001123 goto psx_create_err;
1124 }
Steve French50c2f752007-07-13 00:33:32 +00001125 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001126 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001127 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001128 }
Steve French2dd29d32007-04-23 22:07:35 +00001129
1130psx_create_err:
1131 cifs_buf_release(pSMB);
1132
Steve French65bc98b2009-07-10 15:27:25 +00001133 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001134 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001135 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001136 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001137
1138 if (rc == -EAGAIN)
1139 goto PsxCreat;
1140
Steve French50c2f752007-07-13 00:33:32 +00001141 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001142}
1143
Steve Frencha9d02ad2005-08-24 23:06:05 -07001144static __u16 convert_disposition(int disposition)
1145{
1146 __u16 ofun = 0;
1147
1148 switch (disposition) {
1149 case FILE_SUPERSEDE:
1150 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1151 break;
1152 case FILE_OPEN:
1153 ofun = SMBOPEN_OAPPEND;
1154 break;
1155 case FILE_CREATE:
1156 ofun = SMBOPEN_OCREATE;
1157 break;
1158 case FILE_OPEN_IF:
1159 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1160 break;
1161 case FILE_OVERWRITE:
1162 ofun = SMBOPEN_OTRUNC;
1163 break;
1164 case FILE_OVERWRITE_IF:
1165 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1166 break;
1167 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001168 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169 ofun = SMBOPEN_OAPPEND; /* regular open */
1170 }
1171 return ofun;
1172}
1173
Jeff Layton35fc37d2008-05-14 10:22:03 -07001174static int
1175access_flags_to_smbopen_mode(const int access_flags)
1176{
1177 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1178
1179 if (masked_flags == GENERIC_READ)
1180 return SMBOPEN_READ;
1181 else if (masked_flags == GENERIC_WRITE)
1182 return SMBOPEN_WRITE;
1183
1184 /* just go for read/write */
1185 return SMBOPEN_READWRITE;
1186}
1187
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001189SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001190 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001191 const int access_flags, const int create_options, __u16 *netfid,
1192 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001193 const struct nls_table *nls_codepage, int remap)
1194{
1195 int rc = -EACCES;
1196 OPENX_REQ *pSMB = NULL;
1197 OPENX_RSP *pSMBr = NULL;
1198 int bytes_returned;
1199 int name_len;
1200 __u16 count;
1201
1202OldOpenRetry:
1203 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1204 (void **) &pSMBr);
1205 if (rc)
1206 return rc;
1207
1208 pSMB->AndXCommand = 0xFF; /* none */
1209
1210 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1211 count = 1; /* account for one byte pad to word boundary */
1212 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001213 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1214 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 name_len++; /* trailing null */
1216 name_len *= 2;
1217 } else { /* BB improve check for buffer overruns BB */
1218 count = 0; /* no pad */
1219 name_len = strnlen(fileName, PATH_MAX);
1220 name_len++; /* trailing null */
1221 strncpy(pSMB->fileName, fileName, name_len);
1222 }
1223 if (*pOplock & REQ_OPLOCK)
1224 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001225 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001227
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001229 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1231 /* set file as system file if special file such
1232 as fifo and server expecting SFU style and
1233 no Unix extensions */
1234
Steve French790fe572007-07-07 19:25:05 +00001235 if (create_options & CREATE_OPTION_SPECIAL)
1236 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001237 else /* BB FIXME BB */
1238 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239
Jeff Layton67750fb2008-05-09 22:28:02 +00001240 if (create_options & CREATE_OPTION_READONLY)
1241 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242
1243 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001244/* pSMB->CreateOptions = cpu_to_le32(create_options &
1245 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001247
1248 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001249 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001251 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252
1253 pSMB->ByteCount = cpu_to_le16(count);
1254 /* long_op set to 1 to allow for oplock break timeouts */
1255 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001256 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001257 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001259 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 } else {
1261 /* BB verify if wct == 15 */
1262
Steve French582d21e2008-05-13 04:54:12 +00001263/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264
1265 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1266 /* Let caller know file was created so we can set the mode. */
1267 /* Do we care about the CreateAction in any other cases? */
1268 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001269/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 *pOplock |= CIFS_CREATE_ACTION; */
1271 /* BB FIXME END */
1272
Steve French790fe572007-07-07 19:25:05 +00001273 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1275 pfile_info->LastAccessTime = 0; /* BB fixme */
1276 pfile_info->LastWriteTime = 0; /* BB fixme */
1277 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001278 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001279 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001280 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001281 pfile_info->AllocationSize =
1282 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1283 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001284 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001285 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001286 }
1287 }
1288
1289 cifs_buf_release(pSMB);
1290 if (rc == -EAGAIN)
1291 goto OldOpenRetry;
1292 return rc;
1293}
1294
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001296CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001298 const int access_flags, const int create_options, __u16 *netfid,
1299 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001300 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301{
1302 int rc = -EACCES;
1303 OPEN_REQ *pSMB = NULL;
1304 OPEN_RSP *pSMBr = NULL;
1305 int bytes_returned;
1306 int name_len;
1307 __u16 count;
1308
1309openRetry:
1310 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1311 (void **) &pSMBr);
1312 if (rc)
1313 return rc;
1314
1315 pSMB->AndXCommand = 0xFF; /* none */
1316
1317 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1318 count = 1; /* account for one byte pad to word boundary */
1319 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001320 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1321 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 name_len++; /* trailing null */
1323 name_len *= 2;
1324 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001325 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 count = 0; /* no pad */
1327 name_len = strnlen(fileName, PATH_MAX);
1328 name_len++; /* trailing null */
1329 pSMB->NameLength = cpu_to_le16(name_len);
1330 strncpy(pSMB->fileName, fileName, name_len);
1331 }
1332 if (*pOplock & REQ_OPLOCK)
1333 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001334 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1337 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001338 /* set file as system file if special file such
1339 as fifo and server expecting SFU style and
1340 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001341 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001342 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1343 else
1344 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001345
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /* XP does not handle ATTR_POSIX_SEMANTICS */
1347 /* but it helps speed up case sensitive checks for other
1348 servers such as Samba */
1349 if (tcon->ses->capabilities & CAP_UNIX)
1350 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1351
Jeff Layton67750fb2008-05-09 22:28:02 +00001352 if (create_options & CREATE_OPTION_READONLY)
1353 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1356 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001357 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001358 /* BB Expirement with various impersonation levels and verify */
1359 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 pSMB->SecurityFlags =
1361 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1362
1363 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001364 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 pSMB->ByteCount = cpu_to_le16(count);
1367 /* long_op set to 1 to allow for oplock break timeouts */
1368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001369 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001370 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001372 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 } else {
Steve French09d1db52005-04-28 22:41:08 -07001374 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1376 /* Let caller know file was created so we can set the mode. */
1377 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001378 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001379 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001380 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001381 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1382 36 /* CreationTime to Attributes */);
1383 /* the file_info buf is endian converted by caller */
1384 pfile_info->AllocationSize = pSMBr->AllocationSize;
1385 pfile_info->EndOfFile = pSMBr->EndOfFile;
1386 pfile_info->NumberOfLinks = cpu_to_le32(1);
1387 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 cifs_buf_release(pSMB);
1392 if (rc == -EAGAIN)
1393 goto openRetry;
1394 return rc;
1395}
1396
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001397/*
1398 * Discard any remaining data in the current SMB. To do this, we borrow the
1399 * current bigbuf.
1400 */
1401static int
1402cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1403{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001404 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001405 int remaining = rfclen + 4 - server->total_read;
1406 struct cifs_readdata *rdata = mid->callback_data;
1407
1408 while (remaining > 0) {
1409 int length;
1410
1411 length = cifs_read_from_socket(server, server->bigbuf,
1412 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001413 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001414 if (length < 0)
1415 return length;
1416 server->total_read += length;
1417 remaining -= length;
1418 }
1419
1420 dequeue_mid(mid, rdata->result);
1421 return 0;
1422}
1423
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001424int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1426{
1427 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001428 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001430 char *buf = server->smallbuf;
1431 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432
Joe Perchesf96637b2013-05-04 22:12:25 -05001433 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1434 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001435
1436 /*
1437 * read the rest of READ_RSP header (sans Data array), or whatever we
1438 * can if there's not enough data. At this point, we've read down to
1439 * the Mid.
1440 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001441 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001442 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443
Jeff Layton58195752012-09-19 06:22:34 -07001444 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1445 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446
Jeff Layton58195752012-09-19 06:22:34 -07001447 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448 if (length < 0)
1449 return length;
1450 server->total_read += length;
1451
1452 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001453 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001454 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001455 cifs_dbg(FYI, "%s: server returned error %d\n",
1456 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 return cifs_readv_discard(server, mid);
1458 }
1459
1460 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001461 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001462 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1463 __func__, server->total_read,
1464 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 rdata->result = -EIO;
1466 return cifs_readv_discard(server, mid);
1467 }
1468
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001469 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001470 if (data_offset < server->total_read) {
1471 /*
1472 * win2k8 sometimes sends an offset of 0 when the read
1473 * is beyond the EOF. Treat it as if the data starts just after
1474 * the header.
1475 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001476 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1477 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001478 data_offset = server->total_read;
1479 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1480 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001481 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1482 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001483 rdata->result = -EIO;
1484 return cifs_readv_discard(server, mid);
1485 }
1486
Joe Perchesf96637b2013-05-04 22:12:25 -05001487 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1488 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489
1490 len = data_offset - server->total_read;
1491 if (len > 0) {
1492 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001493 rdata->iov.iov_base = buf + server->total_read;
1494 rdata->iov.iov_len = len;
1495 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001496 if (length < 0)
1497 return length;
1498 server->total_read += length;
1499 }
1500
1501 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001502 rdata->iov.iov_base = buf;
1503 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001504 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1505 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506
1507 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001508 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001509 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001510 /* data_len is corrupt -- discard frame */
1511 rdata->result = -EIO;
1512 return cifs_readv_discard(server, mid);
1513 }
1514
Jeff Layton8321fec2012-09-19 06:22:32 -07001515 length = rdata->read_into_pages(server, rdata, data_len);
1516 if (length < 0)
1517 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001518
Jeff Layton8321fec2012-09-19 06:22:32 -07001519 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520 rdata->bytes = length;
1521
Joe Perchesf96637b2013-05-04 22:12:25 -05001522 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1523 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524
1525 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001526 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001527 return cifs_readv_discard(server, mid);
1528
1529 dequeue_mid(mid, false);
1530 return length;
1531}
1532
1533static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001534cifs_readv_callback(struct mid_q_entry *mid)
1535{
1536 struct cifs_readdata *rdata = mid->callback_data;
1537 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1538 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001539 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1540 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001541 .rq_pages = rdata->pages,
1542 .rq_npages = rdata->nr_pages,
1543 .rq_pagesz = rdata->pagesz,
1544 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545
Joe Perchesf96637b2013-05-04 22:12:25 -05001546 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1547 __func__, mid->mid, mid->mid_state, rdata->result,
1548 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001550 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001551 case MID_RESPONSE_RECEIVED:
1552 /* result already set, check signature */
1553 if (server->sec_mode &
1554 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001555 int rc = 0;
1556
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001557 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001558 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001559 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001560 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1561 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001562 }
1563 /* FIXME: should this be counted toward the initiating task? */
1564 task_io_account_read(rdata->bytes);
1565 cifs_stats_bytes_read(tcon, rdata->bytes);
1566 break;
1567 case MID_REQUEST_SUBMITTED:
1568 case MID_RETRY_NEEDED:
1569 rdata->result = -EAGAIN;
1570 break;
1571 default:
1572 rdata->result = -EIO;
1573 }
1574
Jeff Laytonda472fc2012-03-23 14:40:53 -04001575 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001576 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001577 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001578}
1579
1580/* cifs_async_readv - send an async write, and set up mid to handle result */
1581int
1582cifs_async_readv(struct cifs_readdata *rdata)
1583{
1584 int rc;
1585 READ_REQ *smb = NULL;
1586 int wct;
1587 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001588 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001589 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001590
Joe Perchesf96637b2013-05-04 22:12:25 -05001591 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1592 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001593
1594 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1595 wct = 12;
1596 else {
1597 wct = 10; /* old style read */
1598 if ((rdata->offset >> 32) > 0) {
1599 /* can not handle this big offset for old */
1600 return -EIO;
1601 }
1602 }
1603
1604 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1605 if (rc)
1606 return rc;
1607
1608 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1609 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1610
1611 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001612 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001613 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1614 if (wct == 12)
1615 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1616 smb->Remaining = 0;
1617 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1618 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1619 if (wct == 12)
1620 smb->ByteCount = 0;
1621 else {
1622 /* old style read */
1623 struct smb_com_readx_req *smbr =
1624 (struct smb_com_readx_req *)smb;
1625 smbr->ByteCount = 0;
1626 }
1627
1628 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001629 rdata->iov.iov_base = smb;
1630 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001631
Jeff Layton6993f742012-05-16 07:13:17 -04001632 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001633 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1634 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001635
1636 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001637 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001638 else
1639 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001640
1641 cifs_small_buf_release(smb);
1642 return rc;
1643}
1644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001646CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1647 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648{
1649 int rc = -EACCES;
1650 READ_REQ *pSMB = NULL;
1651 READ_RSP *pSMBr = NULL;
1652 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001653 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001654 int resp_buf_type = 0;
1655 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001656 __u32 pid = io_parms->pid;
1657 __u16 netfid = io_parms->netfid;
1658 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001659 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001660 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Joe Perchesf96637b2013-05-04 22:12:25 -05001662 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001663 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001664 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001665 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001666 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001667 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001668 /* can not handle this big offset for old */
1669 return -EIO;
1670 }
1671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001674 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 if (rc)
1676 return rc;
1677
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001678 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1679 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 /* tcon and ses pointer are checked in smb_init */
1682 if (tcon->ses->server == NULL)
1683 return -ECONNABORTED;
1684
Steve Frenchec637e32005-12-12 20:53:18 -08001685 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001687 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001688 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001689 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 pSMB->Remaining = 0;
1692 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1693 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001694 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001695 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1696 else {
1697 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001698 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001699 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001700 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001701 }
Steve Frenchec637e32005-12-12 20:53:18 -08001702
1703 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001704 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001705 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001706 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001707 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001708 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001710 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 } else {
1712 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1713 data_length = data_length << 16;
1714 data_length += le16_to_cpu(pSMBr->DataLength);
1715 *nbytes = data_length;
1716
1717 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001718 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001720 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001721 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 rc = -EIO;
1723 *nbytes = 0;
1724 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001725 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001726 le16_to_cpu(pSMBr->DataOffset);
1727/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001728 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001729 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001730 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001731 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001732 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 }
1734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Steve French4b8f9302006-02-26 16:41:18 +00001736/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001737 if (*buf) {
1738 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001739 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001740 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001741 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001742 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001743 /* return buffer to caller to free */
1744 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001745 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001746 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001747 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001748 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001749 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001750
1751 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 since file handle passed in no longer valid */
1753 return rc;
1754}
1755
Steve Frenchec637e32005-12-12 20:53:18 -08001756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001758CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001759 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001760 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761{
1762 int rc = -EACCES;
1763 WRITE_REQ *pSMB = NULL;
1764 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001765 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 __u32 bytes_sent;
1767 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001768 __u32 pid = io_parms->pid;
1769 __u16 netfid = io_parms->netfid;
1770 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001771 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001772 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Steve Frencha24e2d72010-04-03 17:20:21 +00001774 *nbytes = 0;
1775
Joe Perchesf96637b2013-05-04 22:12:25 -05001776 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001777 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001778 return -ECONNABORTED;
1779
Steve French790fe572007-07-07 19:25:05 +00001780 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001781 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001782 else {
Steve French1c955182005-08-30 20:58:07 -07001783 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001784 if ((offset >> 32) > 0) {
1785 /* can not handle big offset for old srv */
1786 return -EIO;
1787 }
1788 }
Steve French1c955182005-08-30 20:58:07 -07001789
1790 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 (void **) &pSMBr);
1792 if (rc)
1793 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001794
1795 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1796 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1797
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 /* tcon and ses pointer are checked in smb_init */
1799 if (tcon->ses->server == NULL)
1800 return -ECONNABORTED;
1801
1802 pSMB->AndXCommand = 0xFF; /* none */
1803 pSMB->Fid = netfid;
1804 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001805 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001806 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 pSMB->Reserved = 0xFFFFFFFF;
1809 pSMB->WriteMode = 0;
1810 pSMB->Remaining = 0;
1811
Steve French50c2f752007-07-13 00:33:32 +00001812 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 can send more if LARGE_WRITE_X capability returned by the server and if
1814 our buffer is big enough or if we convert to iovecs on socket writes
1815 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001816 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1818 } else {
1819 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1820 & ~0xFF;
1821 }
1822
1823 if (bytes_sent > count)
1824 bytes_sent = count;
1825 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001826 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001827 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001828 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001829 else if (ubuf) {
1830 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 cifs_buf_release(pSMB);
1832 return -EFAULT;
1833 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001834 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 /* No buffer */
1836 cifs_buf_release(pSMB);
1837 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001838 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001839 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001840 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001841 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001842 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1845 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001846 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001847
Steve French790fe572007-07-07 19:25:05 +00001848 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001849 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001850 else { /* old style write has byte count 4 bytes earlier
1851 so 4 bytes pad */
1852 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001853 (struct smb_com_writex_req *)pSMB;
1854 pSMBW->ByteCount = cpu_to_le16(byte_count);
1855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
1857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1858 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001859 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001861 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 } else {
1863 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1864 *nbytes = (*nbytes) << 16;
1865 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301866
1867 /*
1868 * Mask off high 16 bits when bytes written as returned by the
1869 * server is greater than bytes requested by the client. Some
1870 * OS/2 servers are known to set incorrect CountHigh values.
1871 */
1872 if (*nbytes > count)
1873 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 }
1875
1876 cifs_buf_release(pSMB);
1877
Steve French50c2f752007-07-13 00:33:32 +00001878 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 since file handle passed in no longer valid */
1880
1881 return rc;
1882}
1883
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001884void
1885cifs_writedata_release(struct kref *refcount)
1886{
1887 struct cifs_writedata *wdata = container_of(refcount,
1888 struct cifs_writedata, refcount);
1889
1890 if (wdata->cfile)
1891 cifsFileInfo_put(wdata->cfile);
1892
1893 kfree(wdata);
1894}
1895
1896/*
1897 * Write failed with a retryable error. Resend the write request. It's also
1898 * possible that the page was redirtied so re-clean the page.
1899 */
1900static void
1901cifs_writev_requeue(struct cifs_writedata *wdata)
1902{
1903 int i, rc;
1904 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001905 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001906
1907 for (i = 0; i < wdata->nr_pages; i++) {
1908 lock_page(wdata->pages[i]);
1909 clear_page_dirty_for_io(wdata->pages[i]);
1910 }
1911
1912 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001913 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1914 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001915 } while (rc == -EAGAIN);
1916
1917 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001918 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001919 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001920 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001921 end_page_writeback(wdata->pages[i]);
1922 page_cache_release(wdata->pages[i]);
1923 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001924 }
1925
1926 mapping_set_error(inode->i_mapping, rc);
1927 kref_put(&wdata->refcount, cifs_writedata_release);
1928}
1929
Jeff Laytonc2e87642012-03-23 14:40:55 -04001930void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001931cifs_writev_complete(struct work_struct *work)
1932{
1933 struct cifs_writedata *wdata = container_of(work,
1934 struct cifs_writedata, work);
1935 struct inode *inode = wdata->cfile->dentry->d_inode;
1936 int i = 0;
1937
1938 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001939 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001940 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001941 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001942 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1943 wdata->bytes);
1944 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1945 return cifs_writev_requeue(wdata);
1946
1947 for (i = 0; i < wdata->nr_pages; i++) {
1948 struct page *page = wdata->pages[i];
1949 if (wdata->result == -EAGAIN)
1950 __set_page_dirty_nobuffers(page);
1951 else if (wdata->result < 0)
1952 SetPageError(page);
1953 end_page_writeback(page);
1954 page_cache_release(page);
1955 }
1956 if (wdata->result != -EAGAIN)
1957 mapping_set_error(inode->i_mapping, wdata->result);
1958 kref_put(&wdata->refcount, cifs_writedata_release);
1959}
1960
1961struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001962cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001963{
1964 struct cifs_writedata *wdata;
1965
1966 /* this would overflow */
1967 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001968 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001969 return NULL;
1970 }
1971
1972 /* writedata + number of page pointers */
1973 wdata = kzalloc(sizeof(*wdata) +
1974 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1975 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001977 INIT_LIST_HEAD(&wdata->list);
1978 init_completion(&wdata->done);
1979 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001980 }
1981 return wdata;
1982}
1983
1984/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001985 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001986 * workqueue completion task.
1987 */
1988static void
1989cifs_writev_callback(struct mid_q_entry *mid)
1990{
1991 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001992 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001993 unsigned int written;
1994 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1995
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001996 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001997 case MID_RESPONSE_RECEIVED:
1998 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1999 if (wdata->result != 0)
2000 break;
2001
2002 written = le16_to_cpu(smb->CountHigh);
2003 written <<= 16;
2004 written += le16_to_cpu(smb->Count);
2005 /*
2006 * Mask off high 16 bits when bytes written as returned
2007 * by the server is greater than bytes requested by the
2008 * client. OS/2 servers are known to set incorrect
2009 * CountHigh values.
2010 */
2011 if (written > wdata->bytes)
2012 written &= 0xFFFF;
2013
2014 if (written < wdata->bytes)
2015 wdata->result = -ENOSPC;
2016 else
2017 wdata->bytes = written;
2018 break;
2019 case MID_REQUEST_SUBMITTED:
2020 case MID_RETRY_NEEDED:
2021 wdata->result = -EAGAIN;
2022 break;
2023 default:
2024 wdata->result = -EIO;
2025 break;
2026 }
2027
Jeff Laytonda472fc2012-03-23 14:40:53 -04002028 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002029 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002030 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002031}
2032
2033/* cifs_async_writev - send an async write, and set up mid to handle result */
2034int
2035cifs_async_writev(struct cifs_writedata *wdata)
2036{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002037 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002038 WRITE_REQ *smb = NULL;
2039 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002040 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002041 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002042 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002043
2044 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2045 wct = 14;
2046 } else {
2047 wct = 12;
2048 if (wdata->offset >> 32 > 0) {
2049 /* can not handle big offset for old srv */
2050 return -EIO;
2051 }
2052 }
2053
2054 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2055 if (rc)
2056 goto async_writev_out;
2057
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002058 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2059 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002060
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002061 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002062 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002063 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2064 if (wct == 14)
2065 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2066 smb->Reserved = 0xFFFFFFFF;
2067 smb->WriteMode = 0;
2068 smb->Remaining = 0;
2069
2070 smb->DataOffset =
2071 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2072
2073 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002074 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2075 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076
Jeff Laytoneddb0792012-09-18 16:20:35 -07002077 rqst.rq_iov = &iov;
2078 rqst.rq_nvec = 1;
2079 rqst.rq_pages = wdata->pages;
2080 rqst.rq_npages = wdata->nr_pages;
2081 rqst.rq_pagesz = wdata->pagesz;
2082 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002083
Joe Perchesf96637b2013-05-04 22:12:25 -05002084 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2085 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002086
2087 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2088 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2089
2090 if (wct == 14) {
2091 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2092 put_bcc(wdata->bytes + 1, &smb->hdr);
2093 } else {
2094 /* wct == 12 */
2095 struct smb_com_writex_req *smbw =
2096 (struct smb_com_writex_req *)smb;
2097 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2098 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002099 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002100 }
2101
2102 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002103 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2104 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002105
2106 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002107 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002108 else
2109 kref_put(&wdata->refcount, cifs_writedata_release);
2110
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111async_writev_out:
2112 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002113 return rc;
2114}
2115
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002116int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002117CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002118 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119{
2120 int rc = -EACCES;
2121 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002122 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002123 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002124 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002125 __u32 pid = io_parms->pid;
2126 __u16 netfid = io_parms->netfid;
2127 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002128 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002129 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002131 *nbytes = 0;
2132
Joe Perchesf96637b2013-05-04 22:12:25 -05002133 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002134
Steve French4c3130e2008-12-09 00:28:16 +00002135 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002136 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002137 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002138 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002139 if ((offset >> 32) > 0) {
2140 /* can not handle big offset for old srv */
2141 return -EIO;
2142 }
2143 }
Steve French8cc64c62005-10-03 13:49:43 -07002144 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 if (rc)
2146 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002147
2148 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2149 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2150
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 /* tcon and ses pointer are checked in smb_init */
2152 if (tcon->ses->server == NULL)
2153 return -ECONNABORTED;
2154
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002155 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 pSMB->Fid = netfid;
2157 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002158 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002159 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 pSMB->Reserved = 0xFFFFFFFF;
2161 pSMB->WriteMode = 0;
2162 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002165 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Steve French3e844692005-10-03 13:37:24 -07002167 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2168 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002169 /* header + 1 byte pad */
2170 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002171 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002172 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002173 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002174 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002175 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002176 pSMB->ByteCount = cpu_to_le16(count + 1);
2177 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002178 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002179 (struct smb_com_writex_req *)pSMB;
2180 pSMBW->ByteCount = cpu_to_le16(count + 5);
2181 }
Steve French3e844692005-10-03 13:37:24 -07002182 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002183 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002184 iov[0].iov_len = smb_hdr_len + 4;
2185 else /* wct == 12 pad bigger by four bytes */
2186 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002187
Steve French3e844692005-10-03 13:37:24 -07002188
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002189 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002190 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002192 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002193 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002194 /* presumably this can not happen, but best to be safe */
2195 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002196 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002197 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002198 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2199 *nbytes = (*nbytes) << 16;
2200 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302201
2202 /*
2203 * Mask off high 16 bits when bytes written as returned by the
2204 * server is greater than bytes requested by the client. OS/2
2205 * servers are known to set incorrect CountHigh values.
2206 */
2207 if (*nbytes > count)
2208 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
Steve French4b8f9302006-02-26 16:41:18 +00002211/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002212 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002213 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002214 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002215 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
Steve French50c2f752007-07-13 00:33:32 +00002217 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 since file handle passed in no longer valid */
2219
2220 return rc;
2221}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002222
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002223int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2224 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002225 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2226{
2227 int rc = 0;
2228 LOCK_REQ *pSMB = NULL;
2229 struct kvec iov[2];
2230 int resp_buf_type;
2231 __u16 count;
2232
Joe Perchesf96637b2013-05-04 22:12:25 -05002233 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2234 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002235
2236 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2237 if (rc)
2238 return rc;
2239
2240 pSMB->Timeout = 0;
2241 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2242 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2243 pSMB->LockType = lock_type;
2244 pSMB->AndXCommand = 0xFF; /* none */
2245 pSMB->Fid = netfid; /* netfid stays le */
2246
2247 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2248 inc_rfc1001_len(pSMB, count);
2249 pSMB->ByteCount = cpu_to_le16(count);
2250
2251 iov[0].iov_base = (char *)pSMB;
2252 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2253 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2254 iov[1].iov_base = (char *)buf;
2255 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2256
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002257 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002258 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2259 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002260 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002261
2262 return rc;
2263}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002264
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002266CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002267 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002269 const __u32 numLock, const __u8 lockType,
2270 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271{
2272 int rc = 0;
2273 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002274/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002276 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 __u16 count;
2278
Joe Perchesf96637b2013-05-04 22:12:25 -05002279 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2280 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002281 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2282
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 if (rc)
2284 return rc;
2285
Steve French790fe572007-07-07 19:25:05 +00002286 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002287 /* no response expected */
2288 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002290 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002291 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2293 } else {
2294 pSMB->Timeout = 0;
2295 }
2296
2297 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2298 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2299 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002300 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 pSMB->AndXCommand = 0xFF; /* none */
2302 pSMB->Fid = smb_file_id; /* netfid stays le */
2303
Steve French790fe572007-07-07 19:25:05 +00002304 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002305 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 /* BB where to store pid high? */
2307 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2308 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2309 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2310 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2311 count = sizeof(LOCKING_ANDX_RANGE);
2312 } else {
2313 /* oplock break */
2314 count = 0;
2315 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002316 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 pSMB->ByteCount = cpu_to_le16(count);
2318
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002319 if (waitFlag) {
2320 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002321 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002322 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002323 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002324 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002325 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002326 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002327 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002328 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002329 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330
Steve French50c2f752007-07-13 00:33:32 +00002331 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 since file handle passed in no longer valid */
2333 return rc;
2334}
2335
2336int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002337CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002338 const __u16 smb_file_id, const __u32 netpid,
2339 const loff_t start_offset, const __u64 len,
2340 struct file_lock *pLockData, const __u16 lock_type,
2341 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002342{
2343 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2344 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002345 struct cifs_posix_lock *parm_data;
2346 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002347 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002348 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002349 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002350 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002351 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002352
Joe Perchesf96637b2013-05-04 22:12:25 -05002353 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002354
Steve French08547b02006-02-28 22:39:25 +00002355 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2356
2357 if (rc)
2358 return rc;
2359
2360 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2361
Steve French50c2f752007-07-13 00:33:32 +00002362 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002363 pSMB->MaxSetupCount = 0;
2364 pSMB->Reserved = 0;
2365 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002366 pSMB->Reserved2 = 0;
2367 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2368 offset = param_offset + params;
2369
Steve French08547b02006-02-28 22:39:25 +00002370 count = sizeof(struct cifs_posix_lock);
2371 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002372 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002373 pSMB->SetupCount = 1;
2374 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002375 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002376 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2377 else
2378 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2379 byte_count = 3 /* pad */ + params + count;
2380 pSMB->DataCount = cpu_to_le16(count);
2381 pSMB->ParameterCount = cpu_to_le16(params);
2382 pSMB->TotalDataCount = pSMB->DataCount;
2383 pSMB->TotalParameterCount = pSMB->ParameterCount;
2384 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002385 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002386 (((char *) &pSMB->hdr.Protocol) + offset);
2387
2388 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002389 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002390 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002391 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002392 pSMB->Timeout = cpu_to_le32(-1);
2393 } else
2394 pSMB->Timeout = 0;
2395
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002396 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002397 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002398 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002399
2400 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002401 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002402 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2403 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002404 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002405 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002406 if (waitFlag) {
2407 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2408 (struct smb_hdr *) pSMBr, &bytes_returned);
2409 } else {
Steve French133672e2007-11-13 22:41:37 +00002410 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002411 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002412 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2413 &resp_buf_type, timeout);
2414 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2415 not try to free it twice below on exit */
2416 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002417 }
2418
Steve French08547b02006-02-28 22:39:25 +00002419 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002420 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002421 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002422 /* lock structure can be returned on get */
2423 __u16 data_offset;
2424 __u16 data_count;
2425 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002426
Jeff Layton820a8032011-05-04 08:05:26 -04002427 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002428 rc = -EIO; /* bad smb */
2429 goto plk_err_exit;
2430 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002431 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2432 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002433 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002434 rc = -EIO;
2435 goto plk_err_exit;
2436 }
2437 parm_data = (struct cifs_posix_lock *)
2438 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002439 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002440 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002441 else {
2442 if (parm_data->lock_type ==
2443 __constant_cpu_to_le16(CIFS_RDLCK))
2444 pLockData->fl_type = F_RDLCK;
2445 else if (parm_data->lock_type ==
2446 __constant_cpu_to_le16(CIFS_WRLCK))
2447 pLockData->fl_type = F_WRLCK;
2448
Steve French5443d132011-03-13 05:08:25 +00002449 pLockData->fl_start = le64_to_cpu(parm_data->start);
2450 pLockData->fl_end = pLockData->fl_start +
2451 le64_to_cpu(parm_data->length) - 1;
2452 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002453 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002454 }
Steve French50c2f752007-07-13 00:33:32 +00002455
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002456plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002457 if (pSMB)
2458 cifs_small_buf_release(pSMB);
2459
Steve French133672e2007-11-13 22:41:37 +00002460 if (resp_buf_type == CIFS_SMALL_BUFFER)
2461 cifs_small_buf_release(iov[0].iov_base);
2462 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2463 cifs_buf_release(iov[0].iov_base);
2464
Steve French08547b02006-02-28 22:39:25 +00002465 /* Note: On -EAGAIN error only caller can retry on handle based calls
2466 since file handle passed in no longer valid */
2467
2468 return rc;
2469}
2470
2471
2472int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002473CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474{
2475 int rc = 0;
2476 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002477 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479/* do not retry on dead session on close */
2480 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002481 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 return 0;
2483 if (rc)
2484 return rc;
2485
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002487 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002489 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002490 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002492 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002494 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 }
2496 }
2497
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002499 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 rc = 0;
2501
2502 return rc;
2503}
2504
2505int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002506CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002507{
2508 int rc = 0;
2509 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002510 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002511
2512 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2513 if (rc)
2514 return rc;
2515
2516 pSMB->FileID = (__u16) smb_file_id;
2517 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002518 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002519 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002520 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002521 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002522
2523 return rc;
2524}
2525
2526int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002527CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002528 const char *from_name, const char *to_name,
2529 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530{
2531 int rc = 0;
2532 RENAME_REQ *pSMB = NULL;
2533 RENAME_RSP *pSMBr = NULL;
2534 int bytes_returned;
2535 int name_len, name_len2;
2536 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002537 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Joe Perchesf96637b2013-05-04 22:12:25 -05002539 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540renameRetry:
2541 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2542 (void **) &pSMBr);
2543 if (rc)
2544 return rc;
2545
2546 pSMB->BufferFormat = 0x04;
2547 pSMB->SearchAttributes =
2548 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2549 ATTR_DIRECTORY);
2550
2551 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002552 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2553 from_name, PATH_MAX,
2554 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 name_len++; /* trailing null */
2556 name_len *= 2;
2557 pSMB->OldFileName[name_len] = 0x04; /* pad */
2558 /* protocol requires ASCII signature byte on Unicode string */
2559 pSMB->OldFileName[name_len + 1] = 0x00;
2560 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002561 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002562 to_name, PATH_MAX, cifs_sb->local_nls,
2563 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2565 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002566 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002567 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002569 strncpy(pSMB->OldFileName, from_name, name_len);
2570 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 name_len2++; /* trailing null */
2572 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002573 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 name_len2++; /* trailing null */
2575 name_len2++; /* signature byte */
2576 }
2577
2578 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002579 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 pSMB->ByteCount = cpu_to_le16(count);
2581
2582 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2583 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002584 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002585 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002586 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 cifs_buf_release(pSMB);
2589
2590 if (rc == -EAGAIN)
2591 goto renameRetry;
2592
2593 return rc;
2594}
2595
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002596int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002597 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002598 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599{
2600 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2601 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002602 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 char *data_offset;
2604 char dummy_string[30];
2605 int rc = 0;
2606 int bytes_returned = 0;
2607 int len_of_str;
2608 __u16 params, param_offset, offset, count, byte_count;
2609
Joe Perchesf96637b2013-05-04 22:12:25 -05002610 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2612 (void **) &pSMBr);
2613 if (rc)
2614 return rc;
2615
2616 params = 6;
2617 pSMB->MaxSetupCount = 0;
2618 pSMB->Reserved = 0;
2619 pSMB->Flags = 0;
2620 pSMB->Timeout = 0;
2621 pSMB->Reserved2 = 0;
2622 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2623 offset = param_offset + params;
2624
2625 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2626 rename_info = (struct set_file_rename *) data_offset;
2627 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002628 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 pSMB->SetupCount = 1;
2630 pSMB->Reserved3 = 0;
2631 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2632 byte_count = 3 /* pad */ + params;
2633 pSMB->ParameterCount = cpu_to_le16(params);
2634 pSMB->TotalParameterCount = pSMB->ParameterCount;
2635 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2636 pSMB->DataOffset = cpu_to_le16(offset);
2637 /* construct random name ".cifs_tmp<inodenum><mid>" */
2638 rename_info->overwrite = cpu_to_le32(1);
2639 rename_info->root_fid = 0;
2640 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002641 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002642 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002643 len_of_str =
2644 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002645 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002647 len_of_str =
2648 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002649 target_name, PATH_MAX, nls_codepage,
2650 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 }
2652 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002653 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 byte_count += count;
2655 pSMB->DataCount = cpu_to_le16(count);
2656 pSMB->TotalDataCount = pSMB->DataCount;
2657 pSMB->Fid = netfid;
2658 pSMB->InformationLevel =
2659 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2660 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002661 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 pSMB->ByteCount = cpu_to_le16(byte_count);
2663 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002665 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002666 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002667 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2668 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002669
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 cifs_buf_release(pSMB);
2671
2672 /* Note: On -EAGAIN error only caller can retry on handle based calls
2673 since file handle passed in no longer valid */
2674
2675 return rc;
2676}
2677
2678int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002679CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2680 const char *fromName, const __u16 target_tid, const char *toName,
2681 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682{
2683 int rc = 0;
2684 COPY_REQ *pSMB = NULL;
2685 COPY_RSP *pSMBr = NULL;
2686 int bytes_returned;
2687 int name_len, name_len2;
2688 __u16 count;
2689
Joe Perchesf96637b2013-05-04 22:12:25 -05002690 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691copyRetry:
2692 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2693 (void **) &pSMBr);
2694 if (rc)
2695 return rc;
2696
2697 pSMB->BufferFormat = 0x04;
2698 pSMB->Tid2 = target_tid;
2699
2700 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2701
2702 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002703 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2704 fromName, PATH_MAX, nls_codepage,
2705 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 name_len++; /* trailing null */
2707 name_len *= 2;
2708 pSMB->OldFileName[name_len] = 0x04; /* pad */
2709 /* protocol requires ASCII signature byte on Unicode string */
2710 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002711 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002712 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2713 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2715 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002716 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 name_len = strnlen(fromName, PATH_MAX);
2718 name_len++; /* trailing null */
2719 strncpy(pSMB->OldFileName, fromName, name_len);
2720 name_len2 = strnlen(toName, PATH_MAX);
2721 name_len2++; /* trailing null */
2722 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2723 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2724 name_len2++; /* trailing null */
2725 name_len2++; /* signature byte */
2726 }
2727
2728 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002729 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 pSMB->ByteCount = cpu_to_le16(count);
2731
2732 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2733 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2734 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002735 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2736 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 }
Steve French0d817bc2008-05-22 02:02:03 +00002738 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740 if (rc == -EAGAIN)
2741 goto copyRetry;
2742
2743 return rc;
2744}
2745
2746int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002747CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 const char *fromName, const char *toName,
2749 const struct nls_table *nls_codepage)
2750{
2751 TRANSACTION2_SPI_REQ *pSMB = NULL;
2752 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2753 char *data_offset;
2754 int name_len;
2755 int name_len_target;
2756 int rc = 0;
2757 int bytes_returned = 0;
2758 __u16 params, param_offset, offset, byte_count;
2759
Joe Perchesf96637b2013-05-04 22:12:25 -05002760 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761createSymLinkRetry:
2762 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2763 (void **) &pSMBr);
2764 if (rc)
2765 return rc;
2766
2767 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2768 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002769 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2770 /* find define for this maxpathcomponent */
2771 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 name_len++; /* trailing null */
2773 name_len *= 2;
2774
Steve French50c2f752007-07-13 00:33:32 +00002775 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 name_len = strnlen(fromName, PATH_MAX);
2777 name_len++; /* trailing null */
2778 strncpy(pSMB->FileName, fromName, name_len);
2779 }
2780 params = 6 + name_len;
2781 pSMB->MaxSetupCount = 0;
2782 pSMB->Reserved = 0;
2783 pSMB->Flags = 0;
2784 pSMB->Timeout = 0;
2785 pSMB->Reserved2 = 0;
2786 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002787 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 offset = param_offset + params;
2789
2790 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2791 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2792 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002793 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2794 /* find define for this maxpathcomponent */
2795 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 name_len_target++; /* trailing null */
2797 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002798 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 name_len_target = strnlen(toName, PATH_MAX);
2800 name_len_target++; /* trailing null */
2801 strncpy(data_offset, toName, name_len_target);
2802 }
2803
2804 pSMB->MaxParameterCount = cpu_to_le16(2);
2805 /* BB find exact max on data count below from sess */
2806 pSMB->MaxDataCount = cpu_to_le16(1000);
2807 pSMB->SetupCount = 1;
2808 pSMB->Reserved3 = 0;
2809 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2810 byte_count = 3 /* pad */ + params + name_len_target;
2811 pSMB->DataCount = cpu_to_le16(name_len_target);
2812 pSMB->ParameterCount = cpu_to_le16(params);
2813 pSMB->TotalDataCount = pSMB->DataCount;
2814 pSMB->TotalParameterCount = pSMB->ParameterCount;
2815 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2816 pSMB->DataOffset = cpu_to_le16(offset);
2817 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2818 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002819 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 pSMB->ByteCount = cpu_to_le16(byte_count);
2821 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2822 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002823 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002824 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002825 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2826 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827
Steve French0d817bc2008-05-22 02:02:03 +00002828 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829
2830 if (rc == -EAGAIN)
2831 goto createSymLinkRetry;
2832
2833 return rc;
2834}
2835
2836int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002837CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002839 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840{
2841 TRANSACTION2_SPI_REQ *pSMB = NULL;
2842 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2843 char *data_offset;
2844 int name_len;
2845 int name_len_target;
2846 int rc = 0;
2847 int bytes_returned = 0;
2848 __u16 params, param_offset, offset, byte_count;
2849
Joe Perchesf96637b2013-05-04 22:12:25 -05002850 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851createHardLinkRetry:
2852 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2853 (void **) &pSMBr);
2854 if (rc)
2855 return rc;
2856
2857 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002858 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2859 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 name_len++; /* trailing null */
2861 name_len *= 2;
2862
Steve French50c2f752007-07-13 00:33:32 +00002863 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 name_len = strnlen(toName, PATH_MAX);
2865 name_len++; /* trailing null */
2866 strncpy(pSMB->FileName, toName, name_len);
2867 }
2868 params = 6 + name_len;
2869 pSMB->MaxSetupCount = 0;
2870 pSMB->Reserved = 0;
2871 pSMB->Flags = 0;
2872 pSMB->Timeout = 0;
2873 pSMB->Reserved2 = 0;
2874 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002875 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 offset = param_offset + params;
2877
2878 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2880 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002881 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2882 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 name_len_target++; /* trailing null */
2884 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002885 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 name_len_target = strnlen(fromName, PATH_MAX);
2887 name_len_target++; /* trailing null */
2888 strncpy(data_offset, fromName, name_len_target);
2889 }
2890
2891 pSMB->MaxParameterCount = cpu_to_le16(2);
2892 /* BB find exact max on data count below from sess*/
2893 pSMB->MaxDataCount = cpu_to_le16(1000);
2894 pSMB->SetupCount = 1;
2895 pSMB->Reserved3 = 0;
2896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2897 byte_count = 3 /* pad */ + params + name_len_target;
2898 pSMB->ParameterCount = cpu_to_le16(params);
2899 pSMB->TotalParameterCount = pSMB->ParameterCount;
2900 pSMB->DataCount = cpu_to_le16(name_len_target);
2901 pSMB->TotalDataCount = pSMB->DataCount;
2902 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2903 pSMB->DataOffset = cpu_to_le16(offset);
2904 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2905 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002906 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 pSMB->ByteCount = cpu_to_le16(byte_count);
2908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002910 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002911 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002912 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2913 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
2915 cifs_buf_release(pSMB);
2916 if (rc == -EAGAIN)
2917 goto createHardLinkRetry;
2918
2919 return rc;
2920}
2921
2922int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002923CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002924 const char *from_name, const char *to_name,
2925 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926{
2927 int rc = 0;
2928 NT_RENAME_REQ *pSMB = NULL;
2929 RENAME_RSP *pSMBr = NULL;
2930 int bytes_returned;
2931 int name_len, name_len2;
2932 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002933 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
Joe Perchesf96637b2013-05-04 22:12:25 -05002935 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936winCreateHardLinkRetry:
2937
2938 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2939 (void **) &pSMBr);
2940 if (rc)
2941 return rc;
2942
2943 pSMB->SearchAttributes =
2944 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2945 ATTR_DIRECTORY);
2946 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2947 pSMB->ClusterCount = 0;
2948
2949 pSMB->BufferFormat = 0x04;
2950
2951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2952 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002953 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2954 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 name_len++; /* trailing null */
2956 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002957
2958 /* protocol specifies ASCII buffer format (0x04) for unicode */
2959 pSMB->OldFileName[name_len] = 0x04;
2960 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002962 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002963 to_name, PATH_MAX, cifs_sb->local_nls,
2964 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2966 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002967 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002968 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002970 strncpy(pSMB->OldFileName, from_name, name_len);
2971 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 name_len2++; /* trailing null */
2973 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002974 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 name_len2++; /* trailing null */
2976 name_len2++; /* signature byte */
2977 }
2978
2979 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002980 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 pSMB->ByteCount = cpu_to_le16(count);
2982
2983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002985 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002986 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002987 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002988
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 cifs_buf_release(pSMB);
2990 if (rc == -EAGAIN)
2991 goto winCreateHardLinkRetry;
2992
2993 return rc;
2994}
2995
2996int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002997CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002998 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 const struct nls_table *nls_codepage)
3000{
3001/* SMB_QUERY_FILE_UNIX_LINK */
3002 TRANSACTION2_QPI_REQ *pSMB = NULL;
3003 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3004 int rc = 0;
3005 int bytes_returned;
3006 int name_len;
3007 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003008 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
Joe Perchesf96637b2013-05-04 22:12:25 -05003010 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
3012querySymLinkRetry:
3013 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3014 (void **) &pSMBr);
3015 if (rc)
3016 return rc;
3017
3018 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3019 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003020 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3021 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 name_len++; /* trailing null */
3023 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003024 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 name_len = strnlen(searchName, PATH_MAX);
3026 name_len++; /* trailing null */
3027 strncpy(pSMB->FileName, searchName, name_len);
3028 }
3029
3030 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3031 pSMB->TotalDataCount = 0;
3032 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003033 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 pSMB->MaxSetupCount = 0;
3035 pSMB->Reserved = 0;
3036 pSMB->Flags = 0;
3037 pSMB->Timeout = 0;
3038 pSMB->Reserved2 = 0;
3039 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003040 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 pSMB->DataCount = 0;
3042 pSMB->DataOffset = 0;
3043 pSMB->SetupCount = 1;
3044 pSMB->Reserved3 = 0;
3045 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3046 byte_count = params + 1 /* pad */ ;
3047 pSMB->TotalParameterCount = cpu_to_le16(params);
3048 pSMB->ParameterCount = pSMB->TotalParameterCount;
3049 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3050 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003051 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 pSMB->ByteCount = cpu_to_le16(byte_count);
3053
3054 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3056 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003057 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 } else {
3059 /* decode response */
3060
3061 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003063 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003064 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003066 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003067 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Jeff Layton460b9692009-04-30 07:17:56 -04003069 data_start = ((char *) &pSMBr->hdr.Protocol) +
3070 le16_to_cpu(pSMBr->t2.DataOffset);
3071
Steve French0e0d2cf2009-05-01 05:27:32 +00003072 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3073 is_unicode = true;
3074 else
3075 is_unicode = false;
3076
Steve French737b7582005-04-28 22:41:06 -07003077 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003078 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3079 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003080 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003081 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 }
3083 }
3084 cifs_buf_release(pSMB);
3085 if (rc == -EAGAIN)
3086 goto querySymLinkRetry;
3087 return rc;
3088}
3089
Steve Frenchc52a95542011-02-24 06:16:22 +00003090#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3091/*
3092 * Recent Windows versions now create symlinks more frequently
3093 * and they use the "reparse point" mechanism below. We can of course
3094 * do symlinks nicely to Samba and other servers which support the
3095 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3096 * "MF" symlinks optionally, but for recent Windows we really need to
3097 * reenable the code below and fix the cifs_symlink callers to handle this.
3098 * In the interim this code has been moved to its own config option so
3099 * it is not compiled in by default until callers fixed up and more tested.
3100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003102CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003104 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 const struct nls_table *nls_codepage)
3106{
3107 int rc = 0;
3108 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003109 struct smb_com_transaction_ioctl_req *pSMB;
3110 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
Joe Perchesf96637b2013-05-04 22:12:25 -05003112 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3113 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3115 (void **) &pSMBr);
3116 if (rc)
3117 return rc;
3118
3119 pSMB->TotalParameterCount = 0 ;
3120 pSMB->TotalDataCount = 0;
3121 pSMB->MaxParameterCount = cpu_to_le32(2);
3122 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003123 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 pSMB->MaxSetupCount = 4;
3125 pSMB->Reserved = 0;
3126 pSMB->ParameterOffset = 0;
3127 pSMB->DataCount = 0;
3128 pSMB->DataOffset = 0;
3129 pSMB->SetupCount = 4;
3130 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3131 pSMB->ParameterCount = pSMB->TotalParameterCount;
3132 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3133 pSMB->IsFsctl = 1; /* FSCTL */
3134 pSMB->IsRootFlag = 0;
3135 pSMB->Fid = fid; /* file handle always le */
3136 pSMB->ByteCount = 0;
3137
3138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3139 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3140 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003141 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 } else { /* decode response */
3143 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3144 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003145 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3146 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003148 goto qreparse_out;
3149 }
3150 if (data_count && (data_count < 2048)) {
3151 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003152 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
Steve Frenchafe48c32009-05-02 05:25:46 +00003154 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003155 (struct reparse_data *)
3156 ((char *)&pSMBr->hdr.Protocol
3157 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003158 if ((char *)reparse_buf >= end_of_smb) {
3159 rc = -EIO;
3160 goto qreparse_out;
3161 }
3162 if ((reparse_buf->LinkNamesBuf +
3163 reparse_buf->TargetNameOffset +
3164 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003165 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003166 rc = -EIO;
3167 goto qreparse_out;
3168 }
Steve French50c2f752007-07-13 00:33:32 +00003169
Steve Frenchafe48c32009-05-02 05:25:46 +00003170 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3171 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003172 (reparse_buf->LinkNamesBuf +
3173 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003174 buflen,
3175 reparse_buf->TargetNameLen,
3176 nls_codepage, 0);
3177 } else { /* ASCII names */
3178 strncpy(symlinkinfo,
3179 reparse_buf->LinkNamesBuf +
3180 reparse_buf->TargetNameOffset,
3181 min_t(const int, buflen,
3182 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003184 } else {
3185 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003186 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003188 symlinkinfo[buflen] = 0; /* just in case so the caller
3189 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003190 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 }
Steve French989c7e52009-05-02 05:32:20 +00003192
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003194 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
3196 /* Note: On -EAGAIN error only caller can retry on handle based calls
3197 since file handle passed in no longer valid */
3198
3199 return rc;
3200}
Steve Frenchc52a95542011-02-24 06:16:22 +00003201#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
3203#ifdef CONFIG_CIFS_POSIX
3204
3205/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003206static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3207 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208{
3209 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003210 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3211 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3212 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003213/*
3214 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3215 ace->e_perm, ace->e_tag, ace->e_id);
3216*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
3218 return;
3219}
3220
3221/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003222static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3223 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224{
3225 int size = 0;
3226 int i;
3227 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003228 struct cifs_posix_ace *pACE;
3229 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3230 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
3232 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3233 return -EOPNOTSUPP;
3234
Steve French790fe572007-07-07 19:25:05 +00003235 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 count = le16_to_cpu(cifs_acl->access_entry_count);
3237 pACE = &cifs_acl->ace_array[0];
3238 size = sizeof(struct cifs_posix_acl);
3239 size += sizeof(struct cifs_posix_ace) * count;
3240 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003241 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003242 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3243 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 return -EINVAL;
3245 }
Steve French790fe572007-07-07 19:25:05 +00003246 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 count = le16_to_cpu(cifs_acl->access_entry_count);
3248 size = sizeof(struct cifs_posix_acl);
3249 size += sizeof(struct cifs_posix_ace) * count;
3250/* skip past access ACEs to get to default ACEs */
3251 pACE = &cifs_acl->ace_array[count];
3252 count = le16_to_cpu(cifs_acl->default_entry_count);
3253 size += sizeof(struct cifs_posix_ace) * count;
3254 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003255 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 return -EINVAL;
3257 } else {
3258 /* illegal type */
3259 return -EINVAL;
3260 }
3261
3262 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003263 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003264 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003265 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 return -ERANGE;
3267 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003268 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003269 for (i = 0; i < count ; i++) {
3270 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3271 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 }
3273 }
3274 return size;
3275}
3276
Steve French50c2f752007-07-13 00:33:32 +00003277static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3278 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279{
3280 __u16 rc = 0; /* 0 = ACL converted ok */
3281
Steve Frenchff7feac2005-11-15 16:45:16 -08003282 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3283 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003285 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 /* Probably no need to le convert -1 on any arch but can not hurt */
3287 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003288 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003289 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003290/*
3291 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3292 ace->e_perm, ace->e_tag, ace->e_id);
3293*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 return rc;
3295}
3296
3297/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003298static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3299 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300{
3301 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003302 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3303 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 int count;
3305 int i;
3306
Steve French790fe572007-07-07 19:25:05 +00003307 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 return 0;
3309
3310 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003311 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3312 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003313 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003314 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3315 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 return 0;
3317 }
3318 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003319 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003320 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003321 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003322 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003324 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 return 0;
3326 }
Steve French50c2f752007-07-13 00:33:32 +00003327 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3329 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003330 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 /* ACE not converted */
3332 break;
3333 }
3334 }
Steve French790fe572007-07-07 19:25:05 +00003335 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3337 rc += sizeof(struct cifs_posix_acl);
3338 /* BB add check to make sure ACL does not overflow SMB */
3339 }
3340 return rc;
3341}
3342
3343int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003344CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003345 const unsigned char *searchName,
3346 char *acl_inf, const int buflen, const int acl_type,
3347 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348{
3349/* SMB_QUERY_POSIX_ACL */
3350 TRANSACTION2_QPI_REQ *pSMB = NULL;
3351 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3352 int rc = 0;
3353 int bytes_returned;
3354 int name_len;
3355 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003356
Joe Perchesf96637b2013-05-04 22:12:25 -05003357 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
3359queryAclRetry:
3360 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3361 (void **) &pSMBr);
3362 if (rc)
3363 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003364
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3366 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003367 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3368 searchName, PATH_MAX, nls_codepage,
3369 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 name_len++; /* trailing null */
3371 name_len *= 2;
3372 pSMB->FileName[name_len] = 0;
3373 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003374 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 name_len = strnlen(searchName, PATH_MAX);
3376 name_len++; /* trailing null */
3377 strncpy(pSMB->FileName, searchName, name_len);
3378 }
3379
3380 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3381 pSMB->TotalDataCount = 0;
3382 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003383 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 pSMB->MaxDataCount = cpu_to_le16(4000);
3385 pSMB->MaxSetupCount = 0;
3386 pSMB->Reserved = 0;
3387 pSMB->Flags = 0;
3388 pSMB->Timeout = 0;
3389 pSMB->Reserved2 = 0;
3390 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003391 offsetof(struct smb_com_transaction2_qpi_req,
3392 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 pSMB->DataCount = 0;
3394 pSMB->DataOffset = 0;
3395 pSMB->SetupCount = 1;
3396 pSMB->Reserved3 = 0;
3397 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3398 byte_count = params + 1 /* pad */ ;
3399 pSMB->TotalParameterCount = cpu_to_le16(params);
3400 pSMB->ParameterCount = pSMB->TotalParameterCount;
3401 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3402 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003403 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 pSMB->ByteCount = cpu_to_le16(byte_count);
3405
3406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003408 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003410 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 } else {
3412 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003413
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003416 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 rc = -EIO; /* bad smb */
3418 else {
3419 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3420 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3421 rc = cifs_copy_posix_acl(acl_inf,
3422 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003423 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 }
3425 }
3426 cifs_buf_release(pSMB);
3427 if (rc == -EAGAIN)
3428 goto queryAclRetry;
3429 return rc;
3430}
3431
3432int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003433CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003434 const unsigned char *fileName,
3435 const char *local_acl, const int buflen,
3436 const int acl_type,
3437 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438{
3439 struct smb_com_transaction2_spi_req *pSMB = NULL;
3440 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3441 char *parm_data;
3442 int name_len;
3443 int rc = 0;
3444 int bytes_returned = 0;
3445 __u16 params, byte_count, data_count, param_offset, offset;
3446
Joe Perchesf96637b2013-05-04 22:12:25 -05003447 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448setAclRetry:
3449 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003450 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 if (rc)
3452 return rc;
3453 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3454 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003455 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3456 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 name_len++; /* trailing null */
3458 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003459 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 name_len = strnlen(fileName, PATH_MAX);
3461 name_len++; /* trailing null */
3462 strncpy(pSMB->FileName, fileName, name_len);
3463 }
3464 params = 6 + name_len;
3465 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003466 /* BB find max SMB size from sess */
3467 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 pSMB->MaxSetupCount = 0;
3469 pSMB->Reserved = 0;
3470 pSMB->Flags = 0;
3471 pSMB->Timeout = 0;
3472 pSMB->Reserved2 = 0;
3473 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003474 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 offset = param_offset + params;
3476 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3477 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3478
3479 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003480 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481
Steve French790fe572007-07-07 19:25:05 +00003482 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 rc = -EOPNOTSUPP;
3484 goto setACLerrorExit;
3485 }
3486 pSMB->DataOffset = cpu_to_le16(offset);
3487 pSMB->SetupCount = 1;
3488 pSMB->Reserved3 = 0;
3489 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3490 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3491 byte_count = 3 /* pad */ + params + data_count;
3492 pSMB->DataCount = cpu_to_le16(data_count);
3493 pSMB->TotalDataCount = pSMB->DataCount;
3494 pSMB->ParameterCount = cpu_to_le16(params);
3495 pSMB->TotalParameterCount = pSMB->ParameterCount;
3496 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003497 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 pSMB->ByteCount = cpu_to_le16(byte_count);
3499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003501 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003502 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503
3504setACLerrorExit:
3505 cifs_buf_release(pSMB);
3506 if (rc == -EAGAIN)
3507 goto setAclRetry;
3508 return rc;
3509}
3510
Steve Frenchf654bac2005-04-28 22:41:04 -07003511/* BB fix tabs in this function FIXME BB */
3512int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003513CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003514 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003515{
Steve French50c2f752007-07-13 00:33:32 +00003516 int rc = 0;
3517 struct smb_t2_qfi_req *pSMB = NULL;
3518 struct smb_t2_qfi_rsp *pSMBr = NULL;
3519 int bytes_returned;
3520 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003521
Joe Perchesf96637b2013-05-04 22:12:25 -05003522 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003523 if (tcon == NULL)
3524 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003525
3526GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003527 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3528 (void **) &pSMBr);
3529 if (rc)
3530 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003531
Steve Frenchad7a2922008-02-07 23:25:02 +00003532 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003533 pSMB->t2.TotalDataCount = 0;
3534 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3535 /* BB find exact max data count below from sess structure BB */
3536 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3537 pSMB->t2.MaxSetupCount = 0;
3538 pSMB->t2.Reserved = 0;
3539 pSMB->t2.Flags = 0;
3540 pSMB->t2.Timeout = 0;
3541 pSMB->t2.Reserved2 = 0;
3542 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3543 Fid) - 4);
3544 pSMB->t2.DataCount = 0;
3545 pSMB->t2.DataOffset = 0;
3546 pSMB->t2.SetupCount = 1;
3547 pSMB->t2.Reserved3 = 0;
3548 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3549 byte_count = params + 1 /* pad */ ;
3550 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3551 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3552 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3553 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003554 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003555 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003556 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003557
Steve French790fe572007-07-07 19:25:05 +00003558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3559 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3560 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003561 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003562 } else {
3563 /* decode response */
3564 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003565 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003566 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003567 /* If rc should we check for EOPNOSUPP and
3568 disable the srvino flag? or in caller? */
3569 rc = -EIO; /* bad smb */
3570 else {
3571 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3572 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3573 struct file_chattr_info *pfinfo;
3574 /* BB Do we need a cast or hash here ? */
3575 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003576 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003577 rc = -EIO;
3578 goto GetExtAttrOut;
3579 }
3580 pfinfo = (struct file_chattr_info *)
3581 (data_offset + (char *) &pSMBr->hdr.Protocol);
3582 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003583 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003584 }
3585 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003586GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003587 cifs_buf_release(pSMB);
3588 if (rc == -EAGAIN)
3589 goto GetExtAttrRetry;
3590 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003591}
3592
Steve Frenchf654bac2005-04-28 22:41:04 -07003593#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
Jeff Layton79df1ba2010-12-06 12:52:08 -05003595#ifdef CONFIG_CIFS_ACL
3596/*
3597 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3598 * all NT TRANSACTS that we init here have total parm and data under about 400
3599 * bytes (to fit in small cifs buffer size), which is the case so far, it
3600 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3601 * returned setup area) and MaxParameterCount (returned parms size) must be set
3602 * by caller
3603 */
3604static int
3605smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003606 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003607 void **ret_buf)
3608{
3609 int rc;
3610 __u32 temp_offset;
3611 struct smb_com_ntransact_req *pSMB;
3612
3613 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3614 (void **)&pSMB);
3615 if (rc)
3616 return rc;
3617 *ret_buf = (void *)pSMB;
3618 pSMB->Reserved = 0;
3619 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3620 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003621 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003622 pSMB->ParameterCount = pSMB->TotalParameterCount;
3623 pSMB->DataCount = pSMB->TotalDataCount;
3624 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3625 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3626 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3627 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3628 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3629 pSMB->SubCommand = cpu_to_le16(sub_command);
3630 return 0;
3631}
3632
3633static int
3634validate_ntransact(char *buf, char **ppparm, char **ppdata,
3635 __u32 *pparmlen, __u32 *pdatalen)
3636{
3637 char *end_of_smb;
3638 __u32 data_count, data_offset, parm_count, parm_offset;
3639 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003640 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003641
3642 *pdatalen = 0;
3643 *pparmlen = 0;
3644
3645 if (buf == NULL)
3646 return -EINVAL;
3647
3648 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3649
Jeff Layton820a8032011-05-04 08:05:26 -04003650 bcc = get_bcc(&pSMBr->hdr);
3651 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003652 (char *)&pSMBr->ByteCount;
3653
3654 data_offset = le32_to_cpu(pSMBr->DataOffset);
3655 data_count = le32_to_cpu(pSMBr->DataCount);
3656 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3657 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3658
3659 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3660 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3661
3662 /* should we also check that parm and data areas do not overlap? */
3663 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003664 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003665 return -EINVAL;
3666 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003667 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003668 return -EINVAL;
3669 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003670 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003671 return -EINVAL;
3672 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003673 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3674 *ppdata, data_count, (data_count + *ppdata),
3675 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003676 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003677 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003678 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003679 return -EINVAL;
3680 }
3681 *pdatalen = data_count;
3682 *pparmlen = parm_count;
3683 return 0;
3684}
3685
Steve French0a4b92c2006-01-12 15:44:21 -08003686/* Get Security Descriptor (by handle) from remote server for a file or dir */
3687int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003688CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003689 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003690{
3691 int rc = 0;
3692 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003693 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003694 struct kvec iov[1];
3695
Joe Perchesf96637b2013-05-04 22:12:25 -05003696 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003697
Steve French630f3f0c2007-10-25 21:17:17 +00003698 *pbuflen = 0;
3699 *acl_inf = NULL;
3700
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003701 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003702 8 /* parm len */, tcon, (void **) &pSMB);
3703 if (rc)
3704 return rc;
3705
3706 pSMB->MaxParameterCount = cpu_to_le32(4);
3707 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3708 pSMB->MaxSetupCount = 0;
3709 pSMB->Fid = fid; /* file handle always le */
3710 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3711 CIFS_ACL_DACL);
3712 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003713 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003714 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003715 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003716
Steve Frencha761ac52007-10-18 21:45:27 +00003717 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003718 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003719 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003720 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003721 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003722 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003723 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003724 __u32 parm_len;
3725 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003726 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003727 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003728
3729/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003730 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003731 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003732 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003733 goto qsec_out;
3734 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3735
Joe Perchesf96637b2013-05-04 22:12:25 -05003736 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3737 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003738
3739 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3740 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003741 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003742 goto qsec_out;
3743 }
3744
3745/* BB check that data area is minimum length and as big as acl_len */
3746
Steve Frenchaf6f4612007-10-16 18:40:37 +00003747 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003748 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003749 cifs_dbg(VFS, "acl length %d does not match %d\n",
3750 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003751 if (*pbuflen > acl_len)
3752 *pbuflen = acl_len;
3753 }
Steve French0a4b92c2006-01-12 15:44:21 -08003754
Steve French630f3f0c2007-10-25 21:17:17 +00003755 /* check if buffer is big enough for the acl
3756 header followed by the smallest SID */
3757 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3758 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003759 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003760 rc = -EINVAL;
3761 *pbuflen = 0;
3762 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003763 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003764 if (*acl_inf == NULL) {
3765 *pbuflen = 0;
3766 rc = -ENOMEM;
3767 }
Steve French630f3f0c2007-10-25 21:17:17 +00003768 }
Steve French0a4b92c2006-01-12 15:44:21 -08003769 }
3770qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003771 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003772 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003773 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003774 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003775/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003776 return rc;
3777}
Steve French97837582007-12-31 07:47:21 +00003778
3779int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003780CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003781 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003782{
3783 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3784 int rc = 0;
3785 int bytes_returned = 0;
3786 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003787 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003788
3789setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003790 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003791 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003792 return rc;
Steve French97837582007-12-31 07:47:21 +00003793
3794 pSMB->MaxSetupCount = 0;
3795 pSMB->Reserved = 0;
3796
3797 param_count = 8;
3798 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3799 data_count = acllen;
3800 data_offset = param_offset + param_count;
3801 byte_count = 3 /* pad */ + param_count;
3802
3803 pSMB->DataCount = cpu_to_le32(data_count);
3804 pSMB->TotalDataCount = pSMB->DataCount;
3805 pSMB->MaxParameterCount = cpu_to_le32(4);
3806 pSMB->MaxDataCount = cpu_to_le32(16384);
3807 pSMB->ParameterCount = cpu_to_le32(param_count);
3808 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3809 pSMB->TotalParameterCount = pSMB->ParameterCount;
3810 pSMB->DataOffset = cpu_to_le32(data_offset);
3811 pSMB->SetupCount = 0;
3812 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3813 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3814
3815 pSMB->Fid = fid; /* file handle always le */
3816 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003817 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003818
3819 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003820 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3821 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003822 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003823 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003824 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003825
3826 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3827 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3828
Joe Perchesf96637b2013-05-04 22:12:25 -05003829 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3830 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003831 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003832 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003833 cifs_buf_release(pSMB);
3834
3835 if (rc == -EAGAIN)
3836 goto setCifsAclRetry;
3837
3838 return (rc);
3839}
3840
Jeff Layton79df1ba2010-12-06 12:52:08 -05003841#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003842
Steve French6b8edfe2005-08-23 20:26:03 -07003843/* Legacy Query Path Information call for lookup to old servers such
3844 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003845int
3846SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3847 const char *search_name, FILE_ALL_INFO *data,
3848 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003849{
Steve Frenchad7a2922008-02-07 23:25:02 +00003850 QUERY_INFORMATION_REQ *pSMB;
3851 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003852 int rc = 0;
3853 int bytes_returned;
3854 int name_len;
3855
Joe Perchesf96637b2013-05-04 22:12:25 -05003856 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003857QInfRetry:
3858 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003859 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003860 if (rc)
3861 return rc;
3862
3863 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3864 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003865 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003866 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003867 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003868 name_len++; /* trailing null */
3869 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003870 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003871 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003872 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003873 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003874 }
3875 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003876 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003877 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003878 pSMB->ByteCount = cpu_to_le16(name_len);
3879
3880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003881 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003882 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003883 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003884 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003885 struct timespec ts;
3886 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003887
3888 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003889 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003890 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003891 ts.tv_nsec = 0;
3892 ts.tv_sec = time;
3893 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003894 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3895 data->LastWriteTime = data->ChangeTime;
3896 data->LastAccessTime = 0;
3897 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003898 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003899 data->EndOfFile = data->AllocationSize;
3900 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003901 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003902 } else
3903 rc = -EIO; /* bad buffer passed in */
3904
3905 cifs_buf_release(pSMB);
3906
3907 if (rc == -EAGAIN)
3908 goto QInfRetry;
3909
3910 return rc;
3911}
3912
Jeff Laytonbcd53572010-02-12 07:44:16 -05003913int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003914CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003915 u16 netfid, FILE_ALL_INFO *pFindData)
3916{
3917 struct smb_t2_qfi_req *pSMB = NULL;
3918 struct smb_t2_qfi_rsp *pSMBr = NULL;
3919 int rc = 0;
3920 int bytes_returned;
3921 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003922
Jeff Laytonbcd53572010-02-12 07:44:16 -05003923QFileInfoRetry:
3924 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3925 (void **) &pSMBr);
3926 if (rc)
3927 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003928
Jeff Laytonbcd53572010-02-12 07:44:16 -05003929 params = 2 /* level */ + 2 /* fid */;
3930 pSMB->t2.TotalDataCount = 0;
3931 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3932 /* BB find exact max data count below from sess structure BB */
3933 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3934 pSMB->t2.MaxSetupCount = 0;
3935 pSMB->t2.Reserved = 0;
3936 pSMB->t2.Flags = 0;
3937 pSMB->t2.Timeout = 0;
3938 pSMB->t2.Reserved2 = 0;
3939 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3940 Fid) - 4);
3941 pSMB->t2.DataCount = 0;
3942 pSMB->t2.DataOffset = 0;
3943 pSMB->t2.SetupCount = 1;
3944 pSMB->t2.Reserved3 = 0;
3945 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3946 byte_count = params + 1 /* pad */ ;
3947 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3948 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3949 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3950 pSMB->Pad = 0;
3951 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003952 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003953
3954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3956 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003957 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003958 } else { /* decode response */
3959 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3960
3961 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3962 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003963 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003964 rc = -EIO; /* bad smb */
3965 else if (pFindData) {
3966 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3967 memcpy((char *) pFindData,
3968 (char *) &pSMBr->hdr.Protocol +
3969 data_offset, sizeof(FILE_ALL_INFO));
3970 } else
3971 rc = -ENOMEM;
3972 }
3973 cifs_buf_release(pSMB);
3974 if (rc == -EAGAIN)
3975 goto QFileInfoRetry;
3976
3977 return rc;
3978}
Steve French6b8edfe2005-08-23 20:26:03 -07003979
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003981CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003982 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003983 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003984 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003986 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 TRANSACTION2_QPI_REQ *pSMB = NULL;
3988 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3989 int rc = 0;
3990 int bytes_returned;
3991 int name_len;
3992 __u16 params, byte_count;
3993
Joe Perchesf96637b2013-05-04 22:12:25 -05003994 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995QPathInfoRetry:
3996 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3997 (void **) &pSMBr);
3998 if (rc)
3999 return rc;
4000
4001 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4002 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004003 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004004 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 name_len++; /* trailing null */
4006 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004007 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004008 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004010 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 }
4012
Steve French50c2f752007-07-13 00:33:32 +00004013 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 pSMB->TotalDataCount = 0;
4015 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004016 /* BB find exact max SMB PDU from sess structure BB */
4017 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 pSMB->MaxSetupCount = 0;
4019 pSMB->Reserved = 0;
4020 pSMB->Flags = 0;
4021 pSMB->Timeout = 0;
4022 pSMB->Reserved2 = 0;
4023 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004024 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 pSMB->DataCount = 0;
4026 pSMB->DataOffset = 0;
4027 pSMB->SetupCount = 1;
4028 pSMB->Reserved3 = 0;
4029 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4030 byte_count = params + 1 /* pad */ ;
4031 pSMB->TotalParameterCount = cpu_to_le16(params);
4032 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004033 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004034 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4035 else
4036 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004038 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 pSMB->ByteCount = cpu_to_le16(byte_count);
4040
4041 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4042 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4043 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004044 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 } else { /* decode response */
4046 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4047
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004048 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4049 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004050 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004052 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004053 rc = -EIO; /* 24 or 26 expected but we do not read
4054 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004055 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004056 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004058
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004059 /*
4060 * On legacy responses we do not read the last field,
4061 * EAsize, fortunately since it varies by subdialect and
4062 * also note it differs on Set vs Get, ie two bytes or 4
4063 * bytes depending but we don't care here.
4064 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004065 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004066 size = sizeof(FILE_INFO_STANDARD);
4067 else
4068 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004069 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004070 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 } else
4072 rc = -ENOMEM;
4073 }
4074 cifs_buf_release(pSMB);
4075 if (rc == -EAGAIN)
4076 goto QPathInfoRetry;
4077
4078 return rc;
4079}
4080
4081int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004082CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004083 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4084{
4085 struct smb_t2_qfi_req *pSMB = NULL;
4086 struct smb_t2_qfi_rsp *pSMBr = NULL;
4087 int rc = 0;
4088 int bytes_returned;
4089 __u16 params, byte_count;
4090
4091UnixQFileInfoRetry:
4092 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4093 (void **) &pSMBr);
4094 if (rc)
4095 return rc;
4096
4097 params = 2 /* level */ + 2 /* fid */;
4098 pSMB->t2.TotalDataCount = 0;
4099 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4100 /* BB find exact max data count below from sess structure BB */
4101 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4102 pSMB->t2.MaxSetupCount = 0;
4103 pSMB->t2.Reserved = 0;
4104 pSMB->t2.Flags = 0;
4105 pSMB->t2.Timeout = 0;
4106 pSMB->t2.Reserved2 = 0;
4107 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4108 Fid) - 4);
4109 pSMB->t2.DataCount = 0;
4110 pSMB->t2.DataOffset = 0;
4111 pSMB->t2.SetupCount = 1;
4112 pSMB->t2.Reserved3 = 0;
4113 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4114 byte_count = params + 1 /* pad */ ;
4115 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4116 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4117 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4118 pSMB->Pad = 0;
4119 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004120 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004121
4122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4124 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004125 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004126 } else { /* decode response */
4127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4128
Jeff Layton820a8032011-05-04 08:05:26 -04004129 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004130 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 -05004131 rc = -EIO; /* bad smb */
4132 } else {
4133 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4134 memcpy((char *) pFindData,
4135 (char *) &pSMBr->hdr.Protocol +
4136 data_offset,
4137 sizeof(FILE_UNIX_BASIC_INFO));
4138 }
4139 }
4140
4141 cifs_buf_release(pSMB);
4142 if (rc == -EAGAIN)
4143 goto UnixQFileInfoRetry;
4144
4145 return rc;
4146}
4147
4148int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004149CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004151 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004152 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153{
4154/* SMB_QUERY_FILE_UNIX_BASIC */
4155 TRANSACTION2_QPI_REQ *pSMB = NULL;
4156 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4157 int rc = 0;
4158 int bytes_returned = 0;
4159 int name_len;
4160 __u16 params, byte_count;
4161
Joe Perchesf96637b2013-05-04 22:12:25 -05004162 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163UnixQPathInfoRetry:
4164 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4165 (void **) &pSMBr);
4166 if (rc)
4167 return rc;
4168
4169 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4170 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004171 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4172 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 name_len++; /* trailing null */
4174 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004175 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 name_len = strnlen(searchName, PATH_MAX);
4177 name_len++; /* trailing null */
4178 strncpy(pSMB->FileName, searchName, name_len);
4179 }
4180
Steve French50c2f752007-07-13 00:33:32 +00004181 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 pSMB->TotalDataCount = 0;
4183 pSMB->MaxParameterCount = cpu_to_le16(2);
4184 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004185 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 pSMB->MaxSetupCount = 0;
4187 pSMB->Reserved = 0;
4188 pSMB->Flags = 0;
4189 pSMB->Timeout = 0;
4190 pSMB->Reserved2 = 0;
4191 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004192 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 pSMB->DataCount = 0;
4194 pSMB->DataOffset = 0;
4195 pSMB->SetupCount = 1;
4196 pSMB->Reserved3 = 0;
4197 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4198 byte_count = params + 1 /* pad */ ;
4199 pSMB->TotalParameterCount = cpu_to_le16(params);
4200 pSMB->ParameterCount = pSMB->TotalParameterCount;
4201 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4202 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004203 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 pSMB->ByteCount = cpu_to_le16(byte_count);
4205
4206 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4207 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4208 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004209 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 } else { /* decode response */
4211 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4212
Jeff Layton820a8032011-05-04 08:05:26 -04004213 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004214 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 -07004215 rc = -EIO; /* bad smb */
4216 } else {
4217 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4218 memcpy((char *) pFindData,
4219 (char *) &pSMBr->hdr.Protocol +
4220 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004221 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 }
4223 }
4224 cifs_buf_release(pSMB);
4225 if (rc == -EAGAIN)
4226 goto UnixQPathInfoRetry;
4227
4228 return rc;
4229}
4230
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231/* xid, tcon, searchName and codepage are input parms, rest are returned */
4232int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004233CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004234 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004235 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004236 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237{
4238/* level 257 SMB_ */
4239 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4240 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004241 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 int rc = 0;
4243 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004244 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004246 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247
Joe Perchesf96637b2013-05-04 22:12:25 -05004248 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249
4250findFirstRetry:
4251 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4252 (void **) &pSMBr);
4253 if (rc)
4254 return rc;
4255
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004256 nls_codepage = cifs_sb->local_nls;
4257 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4258
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4260 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004261 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4262 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004263 /* We can not add the asterik earlier in case
4264 it got remapped to 0xF03A as if it were part of the
4265 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004267 if (msearch) {
4268 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4269 pSMB->FileName[name_len+1] = 0;
4270 pSMB->FileName[name_len+2] = '*';
4271 pSMB->FileName[name_len+3] = 0;
4272 name_len += 4; /* now the trailing null */
4273 /* null terminate just in case */
4274 pSMB->FileName[name_len] = 0;
4275 pSMB->FileName[name_len+1] = 0;
4276 name_len += 2;
4277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 } else { /* BB add check for overrun of SMB buf BB */
4279 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004281 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 free buffer exit; BB */
4283 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004284 if (msearch) {
4285 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4286 pSMB->FileName[name_len+1] = '*';
4287 pSMB->FileName[name_len+2] = 0;
4288 name_len += 3;
4289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 }
4291
4292 params = 12 + name_len /* includes null */ ;
4293 pSMB->TotalDataCount = 0; /* no EAs */
4294 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004295 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 pSMB->MaxSetupCount = 0;
4297 pSMB->Reserved = 0;
4298 pSMB->Flags = 0;
4299 pSMB->Timeout = 0;
4300 pSMB->Reserved2 = 0;
4301 byte_count = params + 1 /* pad */ ;
4302 pSMB->TotalParameterCount = cpu_to_le16(params);
4303 pSMB->ParameterCount = pSMB->TotalParameterCount;
4304 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004305 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4306 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 pSMB->DataCount = 0;
4308 pSMB->DataOffset = 0;
4309 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4310 pSMB->Reserved3 = 0;
4311 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4312 pSMB->SearchAttributes =
4313 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4314 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004315 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004316 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4318
4319 /* BB what should we set StorageType to? Does it matter? BB */
4320 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004321 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 pSMB->ByteCount = cpu_to_le16(byte_count);
4323
4324 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4325 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004326 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
Steve French88274812006-03-09 22:21:45 +00004328 if (rc) {/* BB add logic to retry regular search if Unix search
4329 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004331 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004332
Steve French88274812006-03-09 22:21:45 +00004333 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
4335 /* BB eventually could optimize out free and realloc of buf */
4336 /* for this case */
4337 if (rc == -EAGAIN)
4338 goto findFirstRetry;
4339 } else { /* decode response */
4340 /* BB remember to free buffer if error BB */
4341 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004342 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004343 unsigned int lnoff;
4344
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004346 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 else
Steve French4b18f2a2008-04-29 00:06:05 +00004348 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
4350 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004351 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004352 psrch_inf->srch_entries_start =
4353 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4356 le16_to_cpu(pSMBr->t2.ParameterOffset));
4357
Steve French790fe572007-07-07 19:25:05 +00004358 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004359 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 else
Steve French4b18f2a2008-04-29 00:06:05 +00004361 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
Steve French50c2f752007-07-13 00:33:32 +00004363 psrch_inf->entries_in_buffer =
4364 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004365 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004367 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004368 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004369 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004370 psrch_inf->last_entry = NULL;
4371 return rc;
4372 }
4373
Steve French0752f152008-10-07 20:03:33 +00004374 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004375 lnoff;
4376
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004377 if (pnetfid)
4378 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 } else {
4380 cifs_buf_release(pSMB);
4381 }
4382 }
4383
4384 return rc;
4385}
4386
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004387int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4388 __u16 searchHandle, __u16 search_flags,
4389 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390{
4391 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4392 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004393 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 char *response_data;
4395 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004396 int bytes_returned;
4397 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 __u16 params, byte_count;
4399
Joe Perchesf96637b2013-05-04 22:12:25 -05004400 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401
Steve French4b18f2a2008-04-29 00:06:05 +00004402 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 return -ENOENT;
4404
4405 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4406 (void **) &pSMBr);
4407 if (rc)
4408 return rc;
4409
Steve French50c2f752007-07-13 00:33:32 +00004410 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 byte_count = 0;
4412 pSMB->TotalDataCount = 0; /* no EAs */
4413 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004414 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 pSMB->MaxSetupCount = 0;
4416 pSMB->Reserved = 0;
4417 pSMB->Flags = 0;
4418 pSMB->Timeout = 0;
4419 pSMB->Reserved2 = 0;
4420 pSMB->ParameterOffset = cpu_to_le16(
4421 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4422 pSMB->DataCount = 0;
4423 pSMB->DataOffset = 0;
4424 pSMB->SetupCount = 1;
4425 pSMB->Reserved3 = 0;
4426 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4427 pSMB->SearchHandle = searchHandle; /* always kept as le */
4428 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004429 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4431 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004432 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
4434 name_len = psrch_inf->resume_name_len;
4435 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004436 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4438 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004439 /* 14 byte parm len above enough for 2 byte null terminator */
4440 pSMB->ResumeFileName[name_len] = 0;
4441 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 } else {
4443 rc = -EINVAL;
4444 goto FNext2_err_exit;
4445 }
4446 byte_count = params + 1 /* pad */ ;
4447 pSMB->TotalParameterCount = cpu_to_le16(params);
4448 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004449 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004451
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4453 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004454 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 if (rc) {
4456 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004457 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004458 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004459 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004461 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 } else { /* decode response */
4463 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004464
Steve French790fe572007-07-07 19:25:05 +00004465 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004466 unsigned int lnoff;
4467
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 /* BB fixme add lock for file (srch_info) struct here */
4469 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004470 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 else
Steve French4b18f2a2008-04-29 00:06:05 +00004472 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 response_data = (char *) &pSMBr->hdr.Protocol +
4474 le16_to_cpu(pSMBr->t2.ParameterOffset);
4475 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4476 response_data = (char *)&pSMBr->hdr.Protocol +
4477 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004478 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004479 cifs_small_buf_release(
4480 psrch_inf->ntwrk_buf_start);
4481 else
4482 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 psrch_inf->srch_entries_start = response_data;
4484 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004485 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004486 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004487 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 else
Steve French4b18f2a2008-04-29 00:06:05 +00004489 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004490 psrch_inf->entries_in_buffer =
4491 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 psrch_inf->index_of_last_entry +=
4493 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004494 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004495 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004496 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004497 psrch_inf->last_entry = NULL;
4498 return rc;
4499 } else
4500 psrch_inf->last_entry =
4501 psrch_inf->srch_entries_start + lnoff;
4502
Joe Perchesf96637b2013-05-04 22:12:25 -05004503/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4504 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505
4506 /* BB fixme add unlock here */
4507 }
4508
4509 }
4510
4511 /* BB On error, should we leave previous search buf (and count and
4512 last entry fields) intact or free the previous one? */
4513
4514 /* Note: On -EAGAIN error only caller can retry on handle based calls
4515 since file handle passed in no longer valid */
4516FNext2_err_exit:
4517 if (rc != 0)
4518 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 return rc;
4520}
4521
4522int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004523CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004524 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525{
4526 int rc = 0;
4527 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
Joe Perchesf96637b2013-05-04 22:12:25 -05004529 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4531
4532 /* no sense returning error if session restarted
4533 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004534 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 return 0;
4536 if (rc)
4537 return rc;
4538
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 pSMB->FileID = searchHandle;
4540 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004541 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004542 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004543 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004544
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004545 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546
4547 /* Since session is dead, search handle closed on server already */
4548 if (rc == -EAGAIN)
4549 rc = 0;
4550
4551 return rc;
4552}
4553
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004555CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004556 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004557 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558{
4559 int rc = 0;
4560 TRANSACTION2_QPI_REQ *pSMB = NULL;
4561 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4562 int name_len, bytes_returned;
4563 __u16 params, byte_count;
4564
Joe Perchesf96637b2013-05-04 22:12:25 -05004565 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004566 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004567 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568
4569GetInodeNumberRetry:
4570 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004571 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 if (rc)
4573 return rc;
4574
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4576 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004577 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004578 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004579 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 name_len++; /* trailing null */
4581 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004582 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004583 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004585 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 }
4587
4588 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4589 pSMB->TotalDataCount = 0;
4590 pSMB->MaxParameterCount = cpu_to_le16(2);
4591 /* BB find exact max data count below from sess structure BB */
4592 pSMB->MaxDataCount = cpu_to_le16(4000);
4593 pSMB->MaxSetupCount = 0;
4594 pSMB->Reserved = 0;
4595 pSMB->Flags = 0;
4596 pSMB->Timeout = 0;
4597 pSMB->Reserved2 = 0;
4598 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004599 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 pSMB->DataCount = 0;
4601 pSMB->DataOffset = 0;
4602 pSMB->SetupCount = 1;
4603 pSMB->Reserved3 = 0;
4604 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4605 byte_count = params + 1 /* pad */ ;
4606 pSMB->TotalParameterCount = cpu_to_le16(params);
4607 pSMB->ParameterCount = pSMB->TotalParameterCount;
4608 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4609 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004610 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 pSMB->ByteCount = cpu_to_le16(byte_count);
4612
4613 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4614 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4615 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004616 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 } else {
4618 /* decode response */
4619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004621 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 /* If rc should we check for EOPNOSUPP and
4623 disable the srvino flag? or in caller? */
4624 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004625 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4627 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004628 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004630 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004631 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 rc = -EIO;
4633 goto GetInodeNumOut;
4634 }
4635 pfinfo = (struct file_internal_info *)
4636 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004637 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 }
4639 }
4640GetInodeNumOut:
4641 cifs_buf_release(pSMB);
4642 if (rc == -EAGAIN)
4643 goto GetInodeNumberRetry;
4644 return rc;
4645}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646
Igor Mammedovfec45852008-05-16 13:06:30 +04004647/* parses DFS refferal V3 structure
4648 * caller is responsible for freeing target_nodes
4649 * returns:
4650 * on success - 0
4651 * on failure - errno
4652 */
4653static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004654parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004655 unsigned int *num_of_nodes,
4656 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004657 const struct nls_table *nls_codepage, int remap,
4658 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004659{
4660 int i, rc = 0;
4661 char *data_end;
4662 bool is_unicode;
4663 struct dfs_referral_level_3 *ref;
4664
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004665 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4666 is_unicode = true;
4667 else
4668 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004669 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4670
4671 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004672 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4673 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004674 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004675 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004676 }
4677
4678 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004679 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004680 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4681 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004682 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004683 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004684 }
4685
4686 /* get the upper boundary of the resp buffer */
4687 data_end = (char *)(&(pSMBr->PathConsumed)) +
4688 le16_to_cpu(pSMBr->t2.DataCount);
4689
Joe Perchesf96637b2013-05-04 22:12:25 -05004690 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4691 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004692
Joe Perchesf96637b2013-05-04 22:12:25 -05004693 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4694 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004695 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004696 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004697 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004698 }
4699
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004700 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004701 for (i = 0; i < *num_of_nodes; i++) {
4702 char *temp;
4703 int max_len;
4704 struct dfs_info3_param *node = (*target_nodes)+i;
4705
Steve French0e0d2cf2009-05-01 05:27:32 +00004706 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004707 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004708 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4709 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004710 if (tmp == NULL) {
4711 rc = -ENOMEM;
4712 goto parse_DFS_referrals_exit;
4713 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004714 cifsConvertToUTF16((__le16 *) tmp, searchName,
4715 PATH_MAX, nls_codepage, remap);
4716 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004717 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004718 nls_codepage);
4719 kfree(tmp);
4720 } else
4721 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4722
Igor Mammedovfec45852008-05-16 13:06:30 +04004723 node->server_type = le16_to_cpu(ref->ServerType);
4724 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4725
4726 /* copy DfsPath */
4727 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4728 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004729 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4730 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004731 if (!node->path_name) {
4732 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004733 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004734 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004735
4736 /* copy link target UNC */
4737 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4738 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004739 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4740 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004741 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004742 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004743 goto parse_DFS_referrals_exit;
4744 }
4745
4746 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004747 }
4748
Steve Frencha1fe78f2008-05-16 18:48:38 +00004749parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004750 if (rc) {
4751 free_dfs_info_array(*target_nodes, *num_of_nodes);
4752 *target_nodes = NULL;
4753 *num_of_nodes = 0;
4754 }
4755 return rc;
4756}
4757
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004759CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004760 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004761 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004762 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763{
4764/* TRANS2_GET_DFS_REFERRAL */
4765 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4766 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 int rc = 0;
4768 int bytes_returned;
4769 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004771 *num_of_nodes = 0;
4772 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Joe Perchesf96637b2013-05-04 22:12:25 -05004774 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 if (ses == NULL)
4776 return -ENODEV;
4777getDFSRetry:
4778 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4779 (void **) &pSMBr);
4780 if (rc)
4781 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004782
4783 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004784 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004785 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 pSMB->hdr.Tid = ses->ipc_tid;
4787 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004788 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004790 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792
4793 if (ses->capabilities & CAP_UNICODE) {
4794 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4795 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004796 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004797 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004798 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 name_len++; /* trailing null */
4800 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004801 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004802 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004804 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 }
4806
Steve French790fe572007-07-07 19:25:05 +00004807 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004808 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004809 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4810 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4811 }
4812
Steve French50c2f752007-07-13 00:33:32 +00004813 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004814
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 params = 2 /* level */ + name_len /*includes null */ ;
4816 pSMB->TotalDataCount = 0;
4817 pSMB->DataCount = 0;
4818 pSMB->DataOffset = 0;
4819 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004820 /* BB find exact max SMB PDU from sess structure BB */
4821 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 pSMB->MaxSetupCount = 0;
4823 pSMB->Reserved = 0;
4824 pSMB->Flags = 0;
4825 pSMB->Timeout = 0;
4826 pSMB->Reserved2 = 0;
4827 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004828 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 pSMB->SetupCount = 1;
4830 pSMB->Reserved3 = 0;
4831 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4832 byte_count = params + 3 /* pad */ ;
4833 pSMB->ParameterCount = cpu_to_le16(params);
4834 pSMB->TotalParameterCount = pSMB->ParameterCount;
4835 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004836 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 pSMB->ByteCount = cpu_to_le16(byte_count);
4838
4839 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4840 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4841 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004842 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004843 goto GetDFSRefExit;
4844 }
4845 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004847 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004848 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004849 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004850 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004852
Joe Perchesf96637b2013-05-04 22:12:25 -05004853 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4854 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004855
4856 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004857 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004858 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004859 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004860
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004862 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863
4864 if (rc == -EAGAIN)
4865 goto getDFSRetry;
4866
4867 return rc;
4868}
4869
Steve French20962432005-09-21 22:05:57 -07004870/* Query File System Info such as free space to old servers such as Win 9x */
4871int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004872SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4873 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004874{
4875/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4876 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4877 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4878 FILE_SYSTEM_ALLOC_INFO *response_data;
4879 int rc = 0;
4880 int bytes_returned = 0;
4881 __u16 params, byte_count;
4882
Joe Perchesf96637b2013-05-04 22:12:25 -05004883 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004884oldQFSInfoRetry:
4885 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4886 (void **) &pSMBr);
4887 if (rc)
4888 return rc;
Steve French20962432005-09-21 22:05:57 -07004889
4890 params = 2; /* level */
4891 pSMB->TotalDataCount = 0;
4892 pSMB->MaxParameterCount = cpu_to_le16(2);
4893 pSMB->MaxDataCount = cpu_to_le16(1000);
4894 pSMB->MaxSetupCount = 0;
4895 pSMB->Reserved = 0;
4896 pSMB->Flags = 0;
4897 pSMB->Timeout = 0;
4898 pSMB->Reserved2 = 0;
4899 byte_count = params + 1 /* pad */ ;
4900 pSMB->TotalParameterCount = cpu_to_le16(params);
4901 pSMB->ParameterCount = pSMB->TotalParameterCount;
4902 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4903 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4904 pSMB->DataCount = 0;
4905 pSMB->DataOffset = 0;
4906 pSMB->SetupCount = 1;
4907 pSMB->Reserved3 = 0;
4908 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4909 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004910 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004911 pSMB->ByteCount = cpu_to_le16(byte_count);
4912
4913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4915 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004916 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004917 } else { /* decode response */
4918 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4919
Jeff Layton820a8032011-05-04 08:05:26 -04004920 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004921 rc = -EIO; /* bad smb */
4922 else {
4923 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004924 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004925 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004926
Steve French50c2f752007-07-13 00:33:32 +00004927 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004928 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4929 FSData->f_bsize =
4930 le16_to_cpu(response_data->BytesPerSector) *
4931 le32_to_cpu(response_data->
4932 SectorsPerAllocationUnit);
4933 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004934 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004935 FSData->f_bfree = FSData->f_bavail =
4936 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004937 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4938 (unsigned long long)FSData->f_blocks,
4939 (unsigned long long)FSData->f_bfree,
4940 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004941 }
4942 }
4943 cifs_buf_release(pSMB);
4944
4945 if (rc == -EAGAIN)
4946 goto oldQFSInfoRetry;
4947
4948 return rc;
4949}
4950
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004952CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4953 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954{
4955/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4956 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4957 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4958 FILE_SYSTEM_INFO *response_data;
4959 int rc = 0;
4960 int bytes_returned = 0;
4961 __u16 params, byte_count;
4962
Joe Perchesf96637b2013-05-04 22:12:25 -05004963 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964QFSInfoRetry:
4965 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4966 (void **) &pSMBr);
4967 if (rc)
4968 return rc;
4969
4970 params = 2; /* level */
4971 pSMB->TotalDataCount = 0;
4972 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004973 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 pSMB->MaxSetupCount = 0;
4975 pSMB->Reserved = 0;
4976 pSMB->Flags = 0;
4977 pSMB->Timeout = 0;
4978 pSMB->Reserved2 = 0;
4979 byte_count = params + 1 /* pad */ ;
4980 pSMB->TotalParameterCount = cpu_to_le16(params);
4981 pSMB->ParameterCount = pSMB->TotalParameterCount;
4982 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004983 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 pSMB->DataCount = 0;
4985 pSMB->DataOffset = 0;
4986 pSMB->SetupCount = 1;
4987 pSMB->Reserved3 = 0;
4988 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4989 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004990 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 pSMB->ByteCount = cpu_to_le16(byte_count);
4992
4993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4995 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004996 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004998 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999
Jeff Layton820a8032011-05-04 08:05:26 -04005000 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 rc = -EIO; /* bad smb */
5002 else {
5003 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004
5005 response_data =
5006 (FILE_SYSTEM_INFO
5007 *) (((char *) &pSMBr->hdr.Protocol) +
5008 data_offset);
5009 FSData->f_bsize =
5010 le32_to_cpu(response_data->BytesPerSector) *
5011 le32_to_cpu(response_data->
5012 SectorsPerAllocationUnit);
5013 FSData->f_blocks =
5014 le64_to_cpu(response_data->TotalAllocationUnits);
5015 FSData->f_bfree = FSData->f_bavail =
5016 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005017 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5018 (unsigned long long)FSData->f_blocks,
5019 (unsigned long long)FSData->f_bfree,
5020 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 }
5022 }
5023 cifs_buf_release(pSMB);
5024
5025 if (rc == -EAGAIN)
5026 goto QFSInfoRetry;
5027
5028 return rc;
5029}
5030
5031int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005032CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033{
5034/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5035 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5036 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5037 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5038 int rc = 0;
5039 int bytes_returned = 0;
5040 __u16 params, byte_count;
5041
Joe Perchesf96637b2013-05-04 22:12:25 -05005042 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043QFSAttributeRetry:
5044 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5045 (void **) &pSMBr);
5046 if (rc)
5047 return rc;
5048
5049 params = 2; /* level */
5050 pSMB->TotalDataCount = 0;
5051 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005052 /* BB find exact max SMB PDU from sess structure BB */
5053 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 pSMB->MaxSetupCount = 0;
5055 pSMB->Reserved = 0;
5056 pSMB->Flags = 0;
5057 pSMB->Timeout = 0;
5058 pSMB->Reserved2 = 0;
5059 byte_count = params + 1 /* pad */ ;
5060 pSMB->TotalParameterCount = cpu_to_le16(params);
5061 pSMB->ParameterCount = pSMB->TotalParameterCount;
5062 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005063 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 pSMB->DataCount = 0;
5065 pSMB->DataOffset = 0;
5066 pSMB->SetupCount = 1;
5067 pSMB->Reserved3 = 0;
5068 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5069 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005070 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 pSMB->ByteCount = cpu_to_le16(byte_count);
5072
5073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5075 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005076 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 } else { /* decode response */
5078 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5079
Jeff Layton820a8032011-05-04 08:05:26 -04005080 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005081 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 rc = -EIO; /* bad smb */
5083 } else {
5084 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5085 response_data =
5086 (FILE_SYSTEM_ATTRIBUTE_INFO
5087 *) (((char *) &pSMBr->hdr.Protocol) +
5088 data_offset);
5089 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005090 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 }
5092 }
5093 cifs_buf_release(pSMB);
5094
5095 if (rc == -EAGAIN)
5096 goto QFSAttributeRetry;
5097
5098 return rc;
5099}
5100
5101int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005102CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103{
5104/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5105 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5106 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5107 FILE_SYSTEM_DEVICE_INFO *response_data;
5108 int rc = 0;
5109 int bytes_returned = 0;
5110 __u16 params, byte_count;
5111
Joe Perchesf96637b2013-05-04 22:12:25 -05005112 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113QFSDeviceRetry:
5114 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5115 (void **) &pSMBr);
5116 if (rc)
5117 return rc;
5118
5119 params = 2; /* level */
5120 pSMB->TotalDataCount = 0;
5121 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005122 /* BB find exact max SMB PDU from sess structure BB */
5123 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 pSMB->MaxSetupCount = 0;
5125 pSMB->Reserved = 0;
5126 pSMB->Flags = 0;
5127 pSMB->Timeout = 0;
5128 pSMB->Reserved2 = 0;
5129 byte_count = params + 1 /* pad */ ;
5130 pSMB->TotalParameterCount = cpu_to_le16(params);
5131 pSMB->ParameterCount = pSMB->TotalParameterCount;
5132 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005133 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134
5135 pSMB->DataCount = 0;
5136 pSMB->DataOffset = 0;
5137 pSMB->SetupCount = 1;
5138 pSMB->Reserved3 = 0;
5139 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5140 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005141 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 pSMB->ByteCount = cpu_to_le16(byte_count);
5143
5144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5145 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5146 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005147 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 } else { /* decode response */
5149 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5150
Jeff Layton820a8032011-05-04 08:05:26 -04005151 if (rc || get_bcc(&pSMBr->hdr) <
5152 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 rc = -EIO; /* bad smb */
5154 else {
5155 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5156 response_data =
Steve French737b7582005-04-28 22:41:06 -07005157 (FILE_SYSTEM_DEVICE_INFO *)
5158 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 data_offset);
5160 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005161 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 }
5163 }
5164 cifs_buf_release(pSMB);
5165
5166 if (rc == -EAGAIN)
5167 goto QFSDeviceRetry;
5168
5169 return rc;
5170}
5171
5172int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005173CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174{
5175/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5176 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5177 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5178 FILE_SYSTEM_UNIX_INFO *response_data;
5179 int rc = 0;
5180 int bytes_returned = 0;
5181 __u16 params, byte_count;
5182
Joe Perchesf96637b2013-05-04 22:12:25 -05005183 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005185 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5186 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 if (rc)
5188 return rc;
5189
5190 params = 2; /* level */
5191 pSMB->TotalDataCount = 0;
5192 pSMB->DataCount = 0;
5193 pSMB->DataOffset = 0;
5194 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005195 /* BB find exact max SMB PDU from sess structure BB */
5196 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 pSMB->MaxSetupCount = 0;
5198 pSMB->Reserved = 0;
5199 pSMB->Flags = 0;
5200 pSMB->Timeout = 0;
5201 pSMB->Reserved2 = 0;
5202 byte_count = params + 1 /* pad */ ;
5203 pSMB->ParameterCount = cpu_to_le16(params);
5204 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005205 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5206 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pSMB->SetupCount = 1;
5208 pSMB->Reserved3 = 0;
5209 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5210 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005211 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 pSMB->ByteCount = cpu_to_le16(byte_count);
5213
5214 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5215 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5216 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005217 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 } else { /* decode response */
5219 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5220
Jeff Layton820a8032011-05-04 08:05:26 -04005221 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 rc = -EIO; /* bad smb */
5223 } else {
5224 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5225 response_data =
5226 (FILE_SYSTEM_UNIX_INFO
5227 *) (((char *) &pSMBr->hdr.Protocol) +
5228 data_offset);
5229 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005230 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 }
5232 }
5233 cifs_buf_release(pSMB);
5234
5235 if (rc == -EAGAIN)
5236 goto QFSUnixRetry;
5237
5238
5239 return rc;
5240}
5241
Jeremy Allisonac670552005-06-22 17:26:35 -07005242int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005243CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005244{
5245/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5246 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5247 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5248 int rc = 0;
5249 int bytes_returned = 0;
5250 __u16 params, param_offset, offset, byte_count;
5251
Joe Perchesf96637b2013-05-04 22:12:25 -05005252 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005253SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005254 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005255 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5256 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005257 if (rc)
5258 return rc;
5259
5260 params = 4; /* 2 bytes zero followed by info level. */
5261 pSMB->MaxSetupCount = 0;
5262 pSMB->Reserved = 0;
5263 pSMB->Flags = 0;
5264 pSMB->Timeout = 0;
5265 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005266 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5267 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005268 offset = param_offset + params;
5269
5270 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005271 /* BB find exact max SMB PDU from sess structure BB */
5272 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005273 pSMB->SetupCount = 1;
5274 pSMB->Reserved3 = 0;
5275 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5276 byte_count = 1 /* pad */ + params + 12;
5277
5278 pSMB->DataCount = cpu_to_le16(12);
5279 pSMB->ParameterCount = cpu_to_le16(params);
5280 pSMB->TotalDataCount = pSMB->DataCount;
5281 pSMB->TotalParameterCount = pSMB->ParameterCount;
5282 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5283 pSMB->DataOffset = cpu_to_le16(offset);
5284
5285 /* Params. */
5286 pSMB->FileNum = 0;
5287 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5288
5289 /* Data. */
5290 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5291 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5292 pSMB->ClientUnixCap = cpu_to_le64(cap);
5293
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005294 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005295 pSMB->ByteCount = cpu_to_le16(byte_count);
5296
5297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5299 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005300 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005301 } else { /* decode response */
5302 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005303 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005304 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005305 }
5306 cifs_buf_release(pSMB);
5307
5308 if (rc == -EAGAIN)
5309 goto SETFSUnixRetry;
5310
5311 return rc;
5312}
5313
5314
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315
5316int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005317CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005318 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319{
5320/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5321 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5322 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5323 FILE_SYSTEM_POSIX_INFO *response_data;
5324 int rc = 0;
5325 int bytes_returned = 0;
5326 __u16 params, byte_count;
5327
Joe Perchesf96637b2013-05-04 22:12:25 -05005328 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329QFSPosixRetry:
5330 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5331 (void **) &pSMBr);
5332 if (rc)
5333 return rc;
5334
5335 params = 2; /* level */
5336 pSMB->TotalDataCount = 0;
5337 pSMB->DataCount = 0;
5338 pSMB->DataOffset = 0;
5339 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005340 /* BB find exact max SMB PDU from sess structure BB */
5341 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 pSMB->MaxSetupCount = 0;
5343 pSMB->Reserved = 0;
5344 pSMB->Flags = 0;
5345 pSMB->Timeout = 0;
5346 pSMB->Reserved2 = 0;
5347 byte_count = params + 1 /* pad */ ;
5348 pSMB->ParameterCount = cpu_to_le16(params);
5349 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005350 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5351 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 pSMB->SetupCount = 1;
5353 pSMB->Reserved3 = 0;
5354 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5355 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005356 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 pSMB->ByteCount = cpu_to_le16(byte_count);
5358
5359 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5361 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005362 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 } else { /* decode response */
5364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5365
Jeff Layton820a8032011-05-04 08:05:26 -04005366 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 rc = -EIO; /* bad smb */
5368 } else {
5369 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5370 response_data =
5371 (FILE_SYSTEM_POSIX_INFO
5372 *) (((char *) &pSMBr->hdr.Protocol) +
5373 data_offset);
5374 FSData->f_bsize =
5375 le32_to_cpu(response_data->BlockSize);
5376 FSData->f_blocks =
5377 le64_to_cpu(response_data->TotalBlocks);
5378 FSData->f_bfree =
5379 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005380 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 FSData->f_bavail = FSData->f_bfree;
5382 } else {
5383 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005384 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 }
Steve French790fe572007-07-07 19:25:05 +00005386 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005388 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005389 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005391 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 }
5393 }
5394 cifs_buf_release(pSMB);
5395
5396 if (rc == -EAGAIN)
5397 goto QFSPosixRetry;
5398
5399 return rc;
5400}
5401
5402
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005403/*
5404 * We can not use write of zero bytes trick to set file size due to need for
5405 * large file support. Also note that this SetPathInfo is preferred to
5406 * SetFileInfo based method in next routine which is only needed to work around
5407 * a sharing violation bugin Samba which this routine can run into.
5408 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005410CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005411 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5412 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413{
5414 struct smb_com_transaction2_spi_req *pSMB = NULL;
5415 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5416 struct file_end_of_file_info *parm_data;
5417 int name_len;
5418 int rc = 0;
5419 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005420 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5421
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 __u16 params, byte_count, data_count, param_offset, offset;
5423
Joe Perchesf96637b2013-05-04 22:12:25 -05005424 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425SetEOFRetry:
5426 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5427 (void **) &pSMBr);
5428 if (rc)
5429 return rc;
5430
5431 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5432 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005433 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5434 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 name_len++; /* trailing null */
5436 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005437 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005438 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005440 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 }
5442 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005443 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005445 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 pSMB->MaxSetupCount = 0;
5447 pSMB->Reserved = 0;
5448 pSMB->Flags = 0;
5449 pSMB->Timeout = 0;
5450 pSMB->Reserved2 = 0;
5451 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005452 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005454 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005455 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5456 pSMB->InformationLevel =
5457 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5458 else
5459 pSMB->InformationLevel =
5460 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5461 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5463 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005464 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 else
5466 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005467 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 }
5469
5470 parm_data =
5471 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5472 offset);
5473 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5474 pSMB->DataOffset = cpu_to_le16(offset);
5475 pSMB->SetupCount = 1;
5476 pSMB->Reserved3 = 0;
5477 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5478 byte_count = 3 /* pad */ + params + data_count;
5479 pSMB->DataCount = cpu_to_le16(data_count);
5480 pSMB->TotalDataCount = pSMB->DataCount;
5481 pSMB->ParameterCount = cpu_to_le16(params);
5482 pSMB->TotalParameterCount = pSMB->ParameterCount;
5483 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005484 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 parm_data->FileSize = cpu_to_le64(size);
5486 pSMB->ByteCount = cpu_to_le16(byte_count);
5487 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5488 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005489 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005490 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491
5492 cifs_buf_release(pSMB);
5493
5494 if (rc == -EAGAIN)
5495 goto SetEOFRetry;
5496
5497 return rc;
5498}
5499
5500int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005501CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5502 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503{
5504 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 struct file_end_of_file_info *parm_data;
5506 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 __u16 params, param_offset, offset, byte_count, count;
5508
Joe Perchesf96637b2013-05-04 22:12:25 -05005509 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5510 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005511 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5512
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 if (rc)
5514 return rc;
5515
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005516 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5517 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005518
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 params = 6;
5520 pSMB->MaxSetupCount = 0;
5521 pSMB->Reserved = 0;
5522 pSMB->Flags = 0;
5523 pSMB->Timeout = 0;
5524 pSMB->Reserved2 = 0;
5525 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5526 offset = param_offset + params;
5527
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 count = sizeof(struct file_end_of_file_info);
5529 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005530 /* BB find exact max SMB PDU from sess structure BB */
5531 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 pSMB->SetupCount = 1;
5533 pSMB->Reserved3 = 0;
5534 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5535 byte_count = 3 /* pad */ + params + count;
5536 pSMB->DataCount = cpu_to_le16(count);
5537 pSMB->ParameterCount = cpu_to_le16(params);
5538 pSMB->TotalDataCount = pSMB->DataCount;
5539 pSMB->TotalParameterCount = pSMB->ParameterCount;
5540 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5541 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005542 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5543 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 pSMB->DataOffset = cpu_to_le16(offset);
5545 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005546 pSMB->Fid = cfile->fid.netfid;
5547 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5549 pSMB->InformationLevel =
5550 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5551 else
5552 pSMB->InformationLevel =
5553 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005554 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5556 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005557 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 else
5559 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005560 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 }
5562 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005563 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005565 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005567 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5568 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 }
5570
Steve French50c2f752007-07-13 00:33:32 +00005571 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 since file handle passed in no longer valid */
5573
5574 return rc;
5575}
5576
Steve French50c2f752007-07-13 00:33:32 +00005577/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 an open handle, rather than by pathname - this is awkward due to
5579 potential access conflicts on the open, but it is unavoidable for these
5580 old servers since the only other choice is to go from 100 nanosecond DCE
5581 time and resort to the original setpathinfo level which takes the ancient
5582 DOS time format with 2 second granularity */
5583int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005584CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005585 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586{
5587 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 char *data_offset;
5589 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 __u16 params, param_offset, offset, byte_count, count;
5591
Joe Perchesf96637b2013-05-04 22:12:25 -05005592 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005593 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5594
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 if (rc)
5596 return rc;
5597
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005598 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5599 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005600
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 params = 6;
5602 pSMB->MaxSetupCount = 0;
5603 pSMB->Reserved = 0;
5604 pSMB->Flags = 0;
5605 pSMB->Timeout = 0;
5606 pSMB->Reserved2 = 0;
5607 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5608 offset = param_offset + params;
5609
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005610 data_offset = (char *)pSMB +
5611 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612
Steve French26f57362007-08-30 22:09:15 +00005613 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005615 /* BB find max SMB PDU from sess */
5616 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 pSMB->SetupCount = 1;
5618 pSMB->Reserved3 = 0;
5619 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5620 byte_count = 3 /* pad */ + params + count;
5621 pSMB->DataCount = cpu_to_le16(count);
5622 pSMB->ParameterCount = cpu_to_le16(params);
5623 pSMB->TotalDataCount = pSMB->DataCount;
5624 pSMB->TotalParameterCount = pSMB->ParameterCount;
5625 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5626 pSMB->DataOffset = cpu_to_le16(offset);
5627 pSMB->Fid = fid;
5628 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5629 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5630 else
5631 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5632 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005633 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005635 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005636 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005637 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005638 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5639 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
Steve French50c2f752007-07-13 00:33:32 +00005641 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 since file handle passed in no longer valid */
5643
5644 return rc;
5645}
5646
Jeff Layton6d22f092008-09-23 11:48:35 -04005647int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005648CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005649 bool delete_file, __u16 fid, __u32 pid_of_opener)
5650{
5651 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5652 char *data_offset;
5653 int rc = 0;
5654 __u16 params, param_offset, offset, byte_count, count;
5655
Joe Perchesf96637b2013-05-04 22:12:25 -05005656 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005657 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5658
5659 if (rc)
5660 return rc;
5661
5662 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5663 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5664
5665 params = 6;
5666 pSMB->MaxSetupCount = 0;
5667 pSMB->Reserved = 0;
5668 pSMB->Flags = 0;
5669 pSMB->Timeout = 0;
5670 pSMB->Reserved2 = 0;
5671 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5672 offset = param_offset + params;
5673
5674 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5675
5676 count = 1;
5677 pSMB->MaxParameterCount = cpu_to_le16(2);
5678 /* BB find max SMB PDU from sess */
5679 pSMB->MaxDataCount = cpu_to_le16(1000);
5680 pSMB->SetupCount = 1;
5681 pSMB->Reserved3 = 0;
5682 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5683 byte_count = 3 /* pad */ + params + count;
5684 pSMB->DataCount = cpu_to_le16(count);
5685 pSMB->ParameterCount = cpu_to_le16(params);
5686 pSMB->TotalDataCount = pSMB->DataCount;
5687 pSMB->TotalParameterCount = pSMB->ParameterCount;
5688 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5689 pSMB->DataOffset = cpu_to_le16(offset);
5690 pSMB->Fid = fid;
5691 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5692 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005693 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005694 pSMB->ByteCount = cpu_to_le16(byte_count);
5695 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005696 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005697 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005698 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005699
5700 return rc;
5701}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702
5703int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005704CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005705 const char *fileName, const FILE_BASIC_INFO *data,
5706 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707{
5708 TRANSACTION2_SPI_REQ *pSMB = NULL;
5709 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5710 int name_len;
5711 int rc = 0;
5712 int bytes_returned = 0;
5713 char *data_offset;
5714 __u16 params, param_offset, offset, byte_count, count;
5715
Joe Perchesf96637b2013-05-04 22:12:25 -05005716 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
5718SetTimesRetry:
5719 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5720 (void **) &pSMBr);
5721 if (rc)
5722 return rc;
5723
5724 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5725 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005726 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5727 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 name_len++; /* trailing null */
5729 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005730 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 name_len = strnlen(fileName, PATH_MAX);
5732 name_len++; /* trailing null */
5733 strncpy(pSMB->FileName, fileName, name_len);
5734 }
5735
5736 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005737 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005739 /* BB find max SMB PDU from sess structure BB */
5740 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 pSMB->MaxSetupCount = 0;
5742 pSMB->Reserved = 0;
5743 pSMB->Flags = 0;
5744 pSMB->Timeout = 0;
5745 pSMB->Reserved2 = 0;
5746 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005747 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 offset = param_offset + params;
5749 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5750 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5751 pSMB->DataOffset = cpu_to_le16(offset);
5752 pSMB->SetupCount = 1;
5753 pSMB->Reserved3 = 0;
5754 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5755 byte_count = 3 /* pad */ + params + count;
5756
5757 pSMB->DataCount = cpu_to_le16(count);
5758 pSMB->ParameterCount = cpu_to_le16(params);
5759 pSMB->TotalDataCount = pSMB->DataCount;
5760 pSMB->TotalParameterCount = pSMB->ParameterCount;
5761 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5762 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5763 else
5764 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5765 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005766 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005767 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 pSMB->ByteCount = cpu_to_le16(byte_count);
5769 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5770 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005771 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005772 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
5774 cifs_buf_release(pSMB);
5775
5776 if (rc == -EAGAIN)
5777 goto SetTimesRetry;
5778
5779 return rc;
5780}
5781
5782/* Can not be used to set time stamps yet (due to old DOS time format) */
5783/* Can be used to set attributes */
5784#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5785 handling it anyway and NT4 was what we thought it would be needed for
5786 Do not delete it until we prove whether needed for Win9x though */
5787int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005788CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 __u16 dos_attrs, const struct nls_table *nls_codepage)
5790{
5791 SETATTR_REQ *pSMB = NULL;
5792 SETATTR_RSP *pSMBr = NULL;
5793 int rc = 0;
5794 int bytes_returned;
5795 int name_len;
5796
Joe Perchesf96637b2013-05-04 22:12:25 -05005797 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
5799SetAttrLgcyRetry:
5800 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5801 (void **) &pSMBr);
5802 if (rc)
5803 return rc;
5804
5805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5806 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005807 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5808 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 name_len++; /* trailing null */
5810 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005811 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 name_len = strnlen(fileName, PATH_MAX);
5813 name_len++; /* trailing null */
5814 strncpy(pSMB->fileName, fileName, name_len);
5815 }
5816 pSMB->attr = cpu_to_le16(dos_attrs);
5817 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005818 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005822 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005823 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824
5825 cifs_buf_release(pSMB);
5826
5827 if (rc == -EAGAIN)
5828 goto SetAttrLgcyRetry;
5829
5830 return rc;
5831}
5832#endif /* temporarily unneeded SetAttr legacy function */
5833
Jeff Layton654cf142009-07-09 20:02:49 -04005834static void
5835cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5836 const struct cifs_unix_set_info_args *args)
5837{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005838 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005839 u64 mode = args->mode;
5840
Eric W. Biederman49418b22013-02-06 00:57:56 -08005841 if (uid_valid(args->uid))
5842 uid = from_kuid(&init_user_ns, args->uid);
5843 if (gid_valid(args->gid))
5844 gid = from_kgid(&init_user_ns, args->gid);
5845
Jeff Layton654cf142009-07-09 20:02:49 -04005846 /*
5847 * Samba server ignores set of file size to zero due to bugs in some
5848 * older clients, but we should be precise - we use SetFileSize to
5849 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005850 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005851 * zero instead of -1 here
5852 */
5853 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5854 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5855 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5856 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5857 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005858 data_offset->Uid = cpu_to_le64(uid);
5859 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005860 /* better to leave device as zero when it is */
5861 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5862 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5863 data_offset->Permissions = cpu_to_le64(mode);
5864
5865 if (S_ISREG(mode))
5866 data_offset->Type = cpu_to_le32(UNIX_FILE);
5867 else if (S_ISDIR(mode))
5868 data_offset->Type = cpu_to_le32(UNIX_DIR);
5869 else if (S_ISLNK(mode))
5870 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5871 else if (S_ISCHR(mode))
5872 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5873 else if (S_ISBLK(mode))
5874 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5875 else if (S_ISFIFO(mode))
5876 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5877 else if (S_ISSOCK(mode))
5878 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5879}
5880
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005882CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005883 const struct cifs_unix_set_info_args *args,
5884 u16 fid, u32 pid_of_opener)
5885{
5886 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005887 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005888 int rc = 0;
5889 u16 params, param_offset, offset, byte_count, count;
5890
Joe Perchesf96637b2013-05-04 22:12:25 -05005891 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005892 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5893
5894 if (rc)
5895 return rc;
5896
5897 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5898 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5899
5900 params = 6;
5901 pSMB->MaxSetupCount = 0;
5902 pSMB->Reserved = 0;
5903 pSMB->Flags = 0;
5904 pSMB->Timeout = 0;
5905 pSMB->Reserved2 = 0;
5906 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5907 offset = param_offset + params;
5908
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005909 data_offset = (char *)pSMB +
5910 offsetof(struct smb_hdr, Protocol) + offset;
5911
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005912 count = sizeof(FILE_UNIX_BASIC_INFO);
5913
5914 pSMB->MaxParameterCount = cpu_to_le16(2);
5915 /* BB find max SMB PDU from sess */
5916 pSMB->MaxDataCount = cpu_to_le16(1000);
5917 pSMB->SetupCount = 1;
5918 pSMB->Reserved3 = 0;
5919 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5920 byte_count = 3 /* pad */ + params + count;
5921 pSMB->DataCount = cpu_to_le16(count);
5922 pSMB->ParameterCount = cpu_to_le16(params);
5923 pSMB->TotalDataCount = pSMB->DataCount;
5924 pSMB->TotalParameterCount = pSMB->ParameterCount;
5925 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5926 pSMB->DataOffset = cpu_to_le16(offset);
5927 pSMB->Fid = fid;
5928 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5929 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005930 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005931 pSMB->ByteCount = cpu_to_le16(byte_count);
5932
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005933 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005934
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005935 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005936 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005937 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5938 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005939
5940 /* Note: On -EAGAIN error only caller can retry on handle based calls
5941 since file handle passed in no longer valid */
5942
5943 return rc;
5944}
5945
5946int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005947CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005948 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005949 const struct cifs_unix_set_info_args *args,
5950 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951{
5952 TRANSACTION2_SPI_REQ *pSMB = NULL;
5953 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5954 int name_len;
5955 int rc = 0;
5956 int bytes_returned = 0;
5957 FILE_UNIX_BASIC_INFO *data_offset;
5958 __u16 params, param_offset, offset, count, byte_count;
5959
Joe Perchesf96637b2013-05-04 22:12:25 -05005960 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961setPermsRetry:
5962 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5963 (void **) &pSMBr);
5964 if (rc)
5965 return rc;
5966
5967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5968 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005969 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005970 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 name_len++; /* trailing null */
5972 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005973 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005974 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005976 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 }
5978
5979 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005980 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005982 /* BB find max SMB PDU from sess structure BB */
5983 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 pSMB->MaxSetupCount = 0;
5985 pSMB->Reserved = 0;
5986 pSMB->Flags = 0;
5987 pSMB->Timeout = 0;
5988 pSMB->Reserved2 = 0;
5989 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005990 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991 offset = param_offset + params;
5992 data_offset =
5993 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5994 offset);
5995 memset(data_offset, 0, count);
5996 pSMB->DataOffset = cpu_to_le16(offset);
5997 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5998 pSMB->SetupCount = 1;
5999 pSMB->Reserved3 = 0;
6000 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6001 byte_count = 3 /* pad */ + params + count;
6002 pSMB->ParameterCount = cpu_to_le16(params);
6003 pSMB->DataCount = cpu_to_le16(count);
6004 pSMB->TotalParameterCount = pSMB->ParameterCount;
6005 pSMB->TotalDataCount = pSMB->DataCount;
6006 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6007 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006008 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006009
Jeff Layton654cf142009-07-09 20:02:49 -04006010 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011
6012 pSMB->ByteCount = cpu_to_le16(byte_count);
6013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006015 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006016 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017
Steve French0d817bc2008-05-22 02:02:03 +00006018 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 if (rc == -EAGAIN)
6020 goto setPermsRetry;
6021 return rc;
6022}
6023
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006025/*
6026 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6027 * function used by listxattr and getxattr type calls. When ea_name is set,
6028 * it looks for that attribute name and stuffs that value into the EAData
6029 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6030 * buffer. In both cases, the return value is either the length of the
6031 * resulting data or a negative error code. If EAData is a NULL pointer then
6032 * the data isn't copied to it, but the length is returned.
6033 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006035CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006036 const unsigned char *searchName, const unsigned char *ea_name,
6037 char *EAData, size_t buf_size,
6038 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039{
6040 /* BB assumes one setup word */
6041 TRANSACTION2_QPI_REQ *pSMB = NULL;
6042 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6043 int rc = 0;
6044 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006045 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006046 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006047 struct fea *temp_fea;
6048 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006049 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006050 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006051 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052
Joe Perchesf96637b2013-05-04 22:12:25 -05006053 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054QAllEAsRetry:
6055 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6056 (void **) &pSMBr);
6057 if (rc)
6058 return rc;
6059
6060 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006061 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006062 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6063 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006064 list_len++; /* trailing null */
6065 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006067 list_len = strnlen(searchName, PATH_MAX);
6068 list_len++; /* trailing null */
6069 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 }
6071
Jeff Layton6e462b92010-02-10 16:18:26 -05006072 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073 pSMB->TotalDataCount = 0;
6074 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006075 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006076 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 pSMB->MaxSetupCount = 0;
6078 pSMB->Reserved = 0;
6079 pSMB->Flags = 0;
6080 pSMB->Timeout = 0;
6081 pSMB->Reserved2 = 0;
6082 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006083 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084 pSMB->DataCount = 0;
6085 pSMB->DataOffset = 0;
6086 pSMB->SetupCount = 1;
6087 pSMB->Reserved3 = 0;
6088 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6089 byte_count = params + 1 /* pad */ ;
6090 pSMB->TotalParameterCount = cpu_to_le16(params);
6091 pSMB->ParameterCount = pSMB->TotalParameterCount;
6092 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6093 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006094 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 pSMB->ByteCount = cpu_to_le16(byte_count);
6096
6097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6099 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006100 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006101 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006103
6104
6105 /* BB also check enough total bytes returned */
6106 /* BB we need to improve the validity checking
6107 of these trans2 responses */
6108
6109 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006110 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006111 rc = -EIO; /* bad smb */
6112 goto QAllEAsOut;
6113 }
6114
6115 /* check that length of list is not more than bcc */
6116 /* check that each entry does not go beyond length
6117 of list */
6118 /* check that each element of each entry does not
6119 go beyond end of list */
6120 /* validate_trans2_offsets() */
6121 /* BB check if start of smb + data_offset > &bcc+ bcc */
6122
6123 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6124 ea_response_data = (struct fealist *)
6125 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6126
Jeff Layton6e462b92010-02-10 16:18:26 -05006127 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006128 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006129 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006130 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006131 goto QAllEAsOut;
6132 }
6133
Jeff Layton0cd126b2010-02-10 16:18:26 -05006134 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006135 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006136 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006137 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006138 rc = -EIO;
6139 goto QAllEAsOut;
6140 }
6141
Jeff Laytonf0d38682010-02-10 16:18:26 -05006142 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006143 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006144 temp_fea = ea_response_data->list;
6145 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006146 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006147 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006148 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006149
Jeff Layton6e462b92010-02-10 16:18:26 -05006150 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006151 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006152 /* make sure we can read name_len and value_len */
6153 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006154 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006155 rc = -EIO;
6156 goto QAllEAsOut;
6157 }
6158
6159 name_len = temp_fea->name_len;
6160 value_len = le16_to_cpu(temp_fea->value_len);
6161 list_len -= name_len + 1 + value_len;
6162 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006163 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006164 rc = -EIO;
6165 goto QAllEAsOut;
6166 }
6167
Jeff Layton31c05192010-02-10 16:18:26 -05006168 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006169 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006170 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006171 temp_ptr += name_len + 1;
6172 rc = value_len;
6173 if (buf_size == 0)
6174 goto QAllEAsOut;
6175 if ((size_t)value_len > buf_size) {
6176 rc = -ERANGE;
6177 goto QAllEAsOut;
6178 }
6179 memcpy(EAData, temp_ptr, value_len);
6180 goto QAllEAsOut;
6181 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006182 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006183 /* account for prefix user. and trailing null */
6184 rc += (5 + 1 + name_len);
6185 if (rc < (int) buf_size) {
6186 memcpy(EAData, "user.", 5);
6187 EAData += 5;
6188 memcpy(EAData, temp_ptr, name_len);
6189 EAData += name_len;
6190 /* null terminate name */
6191 *EAData = 0;
6192 ++EAData;
6193 } else if (buf_size == 0) {
6194 /* skip copy - calc size only */
6195 } else {
6196 /* stop before overrun buffer */
6197 rc = -ERANGE;
6198 break;
6199 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006200 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006201 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006202 temp_fea = (struct fea *)temp_ptr;
6203 }
6204
Jeff Layton31c05192010-02-10 16:18:26 -05006205 /* didn't find the named attribute */
6206 if (ea_name)
6207 rc = -ENODATA;
6208
Jeff Laytonf0d38682010-02-10 16:18:26 -05006209QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006210 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 if (rc == -EAGAIN)
6212 goto QAllEAsRetry;
6213
6214 return (ssize_t)rc;
6215}
6216
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006218CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6219 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006220 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6221 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222{
6223 struct smb_com_transaction2_spi_req *pSMB = NULL;
6224 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6225 struct fealist *parm_data;
6226 int name_len;
6227 int rc = 0;
6228 int bytes_returned = 0;
6229 __u16 params, param_offset, byte_count, offset, count;
6230
Joe Perchesf96637b2013-05-04 22:12:25 -05006231 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232SetEARetry:
6233 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6234 (void **) &pSMBr);
6235 if (rc)
6236 return rc;
6237
6238 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6239 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006240 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6241 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242 name_len++; /* trailing null */
6243 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006244 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 name_len = strnlen(fileName, PATH_MAX);
6246 name_len++; /* trailing null */
6247 strncpy(pSMB->FileName, fileName, name_len);
6248 }
6249
6250 params = 6 + name_len;
6251
6252 /* done calculating parms using name_len of file name,
6253 now use name_len to calculate length of ea name
6254 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006255 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 name_len = 0;
6257 else
Steve French50c2f752007-07-13 00:33:32 +00006258 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006260 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006262 /* BB find max SMB PDU from sess */
6263 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 pSMB->MaxSetupCount = 0;
6265 pSMB->Reserved = 0;
6266 pSMB->Flags = 0;
6267 pSMB->Timeout = 0;
6268 pSMB->Reserved2 = 0;
6269 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006270 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 offset = param_offset + params;
6272 pSMB->InformationLevel =
6273 cpu_to_le16(SMB_SET_FILE_EA);
6274
6275 parm_data =
6276 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6277 offset);
6278 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6279 pSMB->DataOffset = cpu_to_le16(offset);
6280 pSMB->SetupCount = 1;
6281 pSMB->Reserved3 = 0;
6282 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6283 byte_count = 3 /* pad */ + params + count;
6284 pSMB->DataCount = cpu_to_le16(count);
6285 parm_data->list_len = cpu_to_le32(count);
6286 parm_data->list[0].EA_flags = 0;
6287 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006288 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006290 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006291 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 parm_data->list[0].name[name_len] = 0;
6293 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6294 /* caller ensures that ea_value_len is less than 64K but
6295 we need to ensure that it fits within the smb */
6296
Steve French50c2f752007-07-13 00:33:32 +00006297 /*BB add length check to see if it would fit in
6298 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006299 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6300 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006301 memcpy(parm_data->list[0].name+name_len+1,
6302 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
6304 pSMB->TotalDataCount = pSMB->DataCount;
6305 pSMB->ParameterCount = cpu_to_le16(params);
6306 pSMB->TotalParameterCount = pSMB->ParameterCount;
6307 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006308 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309 pSMB->ByteCount = cpu_to_le16(byte_count);
6310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006312 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006313 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
6315 cifs_buf_release(pSMB);
6316
6317 if (rc == -EAGAIN)
6318 goto SetEARetry;
6319
6320 return rc;
6321}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322#endif
Steve French0eff0e22011-02-24 05:39:23 +00006323
6324#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6325/*
6326 * Years ago the kernel added a "dnotify" function for Samba server,
6327 * to allow network clients (such as Windows) to display updated
6328 * lists of files in directory listings automatically when
6329 * files are added by one user when another user has the
6330 * same directory open on their desktop. The Linux cifs kernel
6331 * client hooked into the kernel side of this interface for
6332 * the same reason, but ironically when the VFS moved from
6333 * "dnotify" to "inotify" it became harder to plug in Linux
6334 * network file system clients (the most obvious use case
6335 * for notify interfaces is when multiple users can update
6336 * the contents of the same directory - exactly what network
6337 * file systems can do) although the server (Samba) could
6338 * still use it. For the short term we leave the worker
6339 * function ifdeffed out (below) until inotify is fixed
6340 * in the VFS to make it easier to plug in network file
6341 * system clients. If inotify turns out to be permanently
6342 * incompatible for network fs clients, we could instead simply
6343 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6344 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006345int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006346 const int notify_subdirs, const __u16 netfid,
6347 __u32 filter, struct file *pfile, int multishot,
6348 const struct nls_table *nls_codepage)
6349{
6350 int rc = 0;
6351 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6352 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6353 struct dir_notify_req *dnotify_req;
6354 int bytes_returned;
6355
Joe Perchesf96637b2013-05-04 22:12:25 -05006356 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006357 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6358 (void **) &pSMBr);
6359 if (rc)
6360 return rc;
6361
6362 pSMB->TotalParameterCount = 0 ;
6363 pSMB->TotalDataCount = 0;
6364 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006365 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006366 pSMB->MaxSetupCount = 4;
6367 pSMB->Reserved = 0;
6368 pSMB->ParameterOffset = 0;
6369 pSMB->DataCount = 0;
6370 pSMB->DataOffset = 0;
6371 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6372 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6373 pSMB->ParameterCount = pSMB->TotalParameterCount;
6374 if (notify_subdirs)
6375 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6376 pSMB->Reserved2 = 0;
6377 pSMB->CompletionFilter = cpu_to_le32(filter);
6378 pSMB->Fid = netfid; /* file handle always le */
6379 pSMB->ByteCount = 0;
6380
6381 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6382 (struct smb_hdr *)pSMBr, &bytes_returned,
6383 CIFS_ASYNC_OP);
6384 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006385 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006386 } else {
6387 /* Add file to outstanding requests */
6388 /* BB change to kmem cache alloc */
6389 dnotify_req = kmalloc(
6390 sizeof(struct dir_notify_req),
6391 GFP_KERNEL);
6392 if (dnotify_req) {
6393 dnotify_req->Pid = pSMB->hdr.Pid;
6394 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6395 dnotify_req->Mid = pSMB->hdr.Mid;
6396 dnotify_req->Tid = pSMB->hdr.Tid;
6397 dnotify_req->Uid = pSMB->hdr.Uid;
6398 dnotify_req->netfid = netfid;
6399 dnotify_req->pfile = pfile;
6400 dnotify_req->filter = filter;
6401 dnotify_req->multishot = multishot;
6402 spin_lock(&GlobalMid_Lock);
6403 list_add_tail(&dnotify_req->lhead,
6404 &GlobalDnotifyReqList);
6405 spin_unlock(&GlobalMid_Lock);
6406 } else
6407 rc = -ENOMEM;
6408 }
6409 cifs_buf_release(pSMB);
6410 return rc;
6411}
6412#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */