blob: dd7e2f61f6078620776d8c942e4929061ae82d27 [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
Jeff Layton9ddec562013-05-26 07:00:58 -0400420int
Jeff Layton38d77c52013-05-26 07:01:00 -0400421cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400422{
Jeff Layton38d77c52013-05-26 07:01:00 -0400423 bool srv_sign_required = server->sec_mode & SECMODE_SIGN_REQUIRED;
424 bool srv_sign_enabled = server->sec_mode & SECMODE_SIGN_ENABLED;
425 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
426
427 /*
428 * Is signing required by mnt options? If not then check
429 * global_secflags to see if it is there.
430 */
431 if (!mnt_sign_required)
432 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
433 CIFSSEC_MUST_SIGN);
434
435 /*
436 * If signing is required then it's automatically enabled too,
437 * otherwise, check to see if the secflags allow it.
438 */
439 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
440 (global_secflags & CIFSSEC_MAY_SIGN);
441
442 /* If server requires signing, does client allow it? */
443 if (srv_sign_required) {
444 if (!mnt_sign_enabled) {
445 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
446 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400447 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400448 server->sign = true;
449 }
450
451 /* If client requires signing, does server allow it? */
452 if (mnt_sign_required) {
453 if (!srv_sign_enabled) {
454 cifs_dbg(VFS, "Server does not support signing!");
455 return -ENOTSUPP;
456 }
457 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400458 }
459
460 return 0;
461}
462
Jeff Layton2190eca2013-05-26 07:00:57 -0400463#ifdef CONFIG_CIFS_WEAK_PW_HASH
464static int
465decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
466 unsigned int secFlags)
467{
468 __s16 tmp;
469 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
470
471 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
472 return -EOPNOTSUPP;
473
474 if ((secFlags & CIFSSEC_MAY_LANMAN) || (secFlags & CIFSSEC_MAY_PLNTXT))
475 server->secType = LANMAN;
476 else {
477 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
478 return -EOPNOTSUPP;
479 }
480 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
481 server->maxReq = min_t(unsigned int,
482 le16_to_cpu(rsp->MaxMpxCount),
483 cifs_max_pending);
484 set_credits(server, server->maxReq);
485 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
486 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
487 /* even though we do not use raw we might as well set this
488 accurately, in case we ever find a need for it */
489 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
490 server->max_rw = 0xFF00;
491 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
492 } else {
493 server->max_rw = 0;/* do not need to use raw anyway */
494 server->capabilities = CAP_MPX_MODE;
495 }
496 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
497 if (tmp == -1) {
498 /* OS/2 often does not set timezone therefore
499 * we must use server time to calc time zone.
500 * Could deviate slightly from the right zone.
501 * Smallest defined timezone difference is 15 minutes
502 * (i.e. Nepal). Rounding up/down is done to match
503 * this requirement.
504 */
505 int val, seconds, remain, result;
506 struct timespec ts, utc;
507 utc = CURRENT_TIME;
508 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
509 rsp->SrvTime.Time, 0);
510 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
511 (int)ts.tv_sec, (int)utc.tv_sec,
512 (int)(utc.tv_sec - ts.tv_sec));
513 val = (int)(utc.tv_sec - ts.tv_sec);
514 seconds = abs(val);
515 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
516 remain = seconds % MIN_TZ_ADJ;
517 if (remain >= (MIN_TZ_ADJ / 2))
518 result += MIN_TZ_ADJ;
519 if (val < 0)
520 result = -result;
521 server->timeAdj = result;
522 } else {
523 server->timeAdj = (int)tmp;
524 server->timeAdj *= 60; /* also in seconds */
525 }
526 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
527
528
529 /* BB get server time for time conversions and add
530 code to use it and timezone since this is not UTC */
531
532 if (rsp->EncryptionKeyLength ==
533 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
534 memcpy(server->cryptkey, rsp->EncryptionKey,
535 CIFS_CRYPTO_KEY_SIZE);
536 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
537 return -EIO; /* need cryptkey unless plain text */
538 }
539
540 cifs_dbg(FYI, "LANMAN negotiated\n");
541 return 0;
542}
543#else
544static inline int
545decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
546 unsigned int secFlags)
547{
548 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
549 return -EOPNOTSUPP;
550}
551#endif
552
Jeff Layton91934002013-05-26 07:00:58 -0400553static bool
554should_set_ext_sec_flag(unsigned int secFlags)
555{
556 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
557 return true;
558 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5)
559 return true;
560 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
561 return true;
562 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP)
563 return true;
564 return false;
565}
566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400568CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
570 NEGOTIATE_REQ *pSMB;
571 NEGOTIATE_RSP *pSMBr;
572 int rc = 0;
573 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000574 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400575 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000577 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Jeff Layton3534b852013-05-24 07:41:01 -0400579 if (!server) {
580 WARN(1, "%s: server is NULL!\n", __func__);
581 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 }
Jeff Layton3534b852013-05-24 07:41:01 -0400583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
585 (void **) &pSMB, (void **) &pSMBr);
586 if (rc)
587 return rc;
Steve French750d1152006-06-27 06:28:30 +0000588
589 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000590 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000591 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000592 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400593 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000594
Joe Perchesf96637b2013-05-04 22:12:25 -0500595 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000596
Pavel Shilovsky88257362012-05-23 14:01:59 +0400597 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000598 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000599
Jeff Layton91934002013-05-26 07:00:58 -0400600 if (should_set_ext_sec_flag(secFlags)) {
601 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000602 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
603 }
Steve French50c2f752007-07-13 00:33:32 +0000604
Steve French39798772006-05-31 22:40:51 +0000605 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000606 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000607 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
608 count += strlen(protocols[i].name) + 1;
609 /* null at end of source and target buffers anyway */
610 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000611 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 pSMB->ByteCount = cpu_to_le16(count);
613
614 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000616 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000617 goto neg_err_exit;
618
Jeff Layton9bf67e52010-04-24 07:57:46 -0400619 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500620 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000621 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400622 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000623 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000624 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000625 could not negotiate a common dialect */
626 rc = -EOPNOTSUPP;
627 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000628 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400629 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton2190eca2013-05-26 07:00:57 -0400630 rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
Jeff Layton9ddec562013-05-26 07:00:58 -0400631 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000632 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000633 /* unknown wct */
634 rc = -EOPNOTSUPP;
635 goto neg_err_exit;
636 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400637 /* else wct == 17, NTLM or better */
638
Steve French96daf2b2011-05-27 04:34:02 +0000639 server->sec_mode = pSMBr->SecurityMode;
640 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500641 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000642
Steve French96daf2b2011-05-27 04:34:02 +0000643 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000644#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000645 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000646#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500647 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000648
Steve French790fe572007-07-07 19:25:05 +0000649 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000650 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000651 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000652 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000653 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000654 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000655 else if (secFlags & CIFSSEC_MAY_KRB5)
656 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000657 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000658 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000659 else if (secFlags & CIFSSEC_MAY_LANMAN)
660 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000661 else {
662 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500663 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000664 goto neg_err_exit;
665 }
666 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000667
Steve French254e55e2006-06-04 05:53:15 +0000668 /* one byte, so no need to convert this or EncryptionKeyLen from
669 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300670 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
671 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400672 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000673 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400674 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000675 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500676 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000677 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000678 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
679 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400680
Jeff Laytone598d1d82013-05-26 07:00:59 -0400681 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
682 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500683 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000684 CIFS_CRYPTO_KEY_SIZE);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400685 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000686 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Laytone598d1d82013-05-26 07:00:59 -0400687 (pSMBr->EncryptionKeyLength == 0)) {
688 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400689 rc = decode_ext_sec_blob(server, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400690 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000691 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400692 } else {
693 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000694 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400695 }
Steve French254e55e2006-06-04 05:53:15 +0000696
697signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400698 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400699 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000700neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700701 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000702
Joe Perchesf96637b2013-05-04 22:12:25 -0500703 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return rc;
705}
706
707int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400708CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
710 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Joe Perchesf96637b2013-05-04 22:12:25 -0500713 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500714
715 /* BB: do we need to check this? These should never be NULL. */
716 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
717 return -EIO;
718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500720 * No need to return error on this operation if tid invalidated and
721 * closed on server already e.g. due to tcp session crashing. Also,
722 * the tcon is no longer on the list, so no need to take lock before
723 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 */
Steve French268875b2009-06-25 00:29:21 +0000725 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000726 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
Steve French50c2f752007-07-13 00:33:32 +0000728 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700729 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500730 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return rc;
Steve French133672e2007-11-13 22:41:37 +0000732
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400733 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500735 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Steve French50c2f752007-07-13 00:33:32 +0000737 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500738 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 if (rc == -EAGAIN)
740 rc = 0;
741
742 return rc;
743}
744
Jeff Layton766fdbb2011-01-11 07:24:21 -0500745/*
746 * This is a no-op for now. We're not really interested in the reply, but
747 * rather in the fact that the server sent one and that server->lstrp
748 * gets updated.
749 *
750 * FIXME: maybe we should consider checking that the reply matches request?
751 */
752static void
753cifs_echo_callback(struct mid_q_entry *mid)
754{
755 struct TCP_Server_Info *server = mid->callback_data;
756
757 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400758 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500759}
760
761int
762CIFSSMBEcho(struct TCP_Server_Info *server)
763{
764 ECHO_REQ *smb;
765 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400766 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700767 struct smb_rqst rqst = { .rq_iov = &iov,
768 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500769
Joe Perchesf96637b2013-05-04 22:12:25 -0500770 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500771
772 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
773 if (rc)
774 return rc;
775
776 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000777 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500778 smb->hdr.WordCount = 1;
779 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400780 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500781 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000782 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400783 iov.iov_base = smb;
784 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500785
Jeff Laytonfec344e2012-09-18 16:20:35 -0700786 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400787 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500788 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500789 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500790
791 cifs_small_buf_release(smb);
792
793 return rc;
794}
795
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400797CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 LOGOFF_ANDX_REQ *pSMB;
800 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Joe Perchesf96637b2013-05-04 22:12:25 -0500802 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500803
804 /*
805 * BB: do we need to check validity of ses and server? They should
806 * always be valid since we have an active reference. If not, that
807 * should probably be a BUG()
808 */
809 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return -EIO;
811
Steve Frenchd7b619c2010-02-25 05:36:46 +0000812 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000813 if (ses->need_reconnect)
814 goto session_already_dead; /* no need to send SMBlogoff if uid
815 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
817 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000818 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return rc;
820 }
821
Pavel Shilovsky88257362012-05-23 14:01:59 +0400822 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700823
Jeff Layton38d77c52013-05-26 07:01:00 -0400824 if (ses->server->sign)
825 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
827 pSMB->hdr.Uid = ses->Suid;
828
829 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400830 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000831session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000832 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000835 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 error */
837 if (rc == -EAGAIN)
838 rc = 0;
839 return rc;
840}
841
842int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400843CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
844 const char *fileName, __u16 type,
845 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000846{
847 TRANSACTION2_SPI_REQ *pSMB = NULL;
848 TRANSACTION2_SPI_RSP *pSMBr = NULL;
849 struct unlink_psx_rq *pRqD;
850 int name_len;
851 int rc = 0;
852 int bytes_returned = 0;
853 __u16 params, param_offset, offset, byte_count;
854
Joe Perchesf96637b2013-05-04 22:12:25 -0500855 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000856PsxDelete:
857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
858 (void **) &pSMBr);
859 if (rc)
860 return rc;
861
862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
863 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600864 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
865 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000866 name_len++; /* trailing null */
867 name_len *= 2;
868 } else { /* BB add path length overrun check */
869 name_len = strnlen(fileName, PATH_MAX);
870 name_len++; /* trailing null */
871 strncpy(pSMB->FileName, fileName, name_len);
872 }
873
874 params = 6 + name_len;
875 pSMB->MaxParameterCount = cpu_to_le16(2);
876 pSMB->MaxDataCount = 0; /* BB double check this with jra */
877 pSMB->MaxSetupCount = 0;
878 pSMB->Reserved = 0;
879 pSMB->Flags = 0;
880 pSMB->Timeout = 0;
881 pSMB->Reserved2 = 0;
882 param_offset = offsetof(struct smb_com_transaction2_spi_req,
883 InformationLevel) - 4;
884 offset = param_offset + params;
885
886 /* Setup pointer to Request Data (inode type) */
887 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
888 pRqD->type = cpu_to_le16(type);
889 pSMB->ParameterOffset = cpu_to_le16(param_offset);
890 pSMB->DataOffset = cpu_to_le16(offset);
891 pSMB->SetupCount = 1;
892 pSMB->Reserved3 = 0;
893 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
894 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
895
896 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
897 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
898 pSMB->ParameterCount = cpu_to_le16(params);
899 pSMB->TotalParameterCount = pSMB->ParameterCount;
900 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
901 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000902 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000903 pSMB->ByteCount = cpu_to_le16(byte_count);
904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000906 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500907 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000908 cifs_buf_release(pSMB);
909
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400910 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000911
912 if (rc == -EAGAIN)
913 goto PsxDelete;
914
915 return rc;
916}
917
918int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700919CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
920 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
922 DELETE_FILE_REQ *pSMB = NULL;
923 DELETE_FILE_RSP *pSMBr = NULL;
924 int rc = 0;
925 int bytes_returned;
926 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700927 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
929DelFileRetry:
930 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
931 (void **) &pSMBr);
932 if (rc)
933 return rc;
934
935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700936 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
937 PATH_MAX, cifs_sb->local_nls,
938 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 name_len++; /* trailing null */
940 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700941 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700942 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700944 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946 pSMB->SearchAttributes =
947 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
948 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000949 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 pSMB->ByteCount = cpu_to_le16(name_len + 1);
951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400953 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000954 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500955 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 cifs_buf_release(pSMB);
958 if (rc == -EAGAIN)
959 goto DelFileRetry;
960
961 return rc;
962}
963
964int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400965CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
966 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
968 DELETE_DIRECTORY_REQ *pSMB = NULL;
969 DELETE_DIRECTORY_RSP *pSMBr = NULL;
970 int rc = 0;
971 int bytes_returned;
972 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400973 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Joe Perchesf96637b2013-05-04 22:12:25 -0500975 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976RmDirRetry:
977 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
978 (void **) &pSMBr);
979 if (rc)
980 return rc;
981
982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400983 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
984 PATH_MAX, cifs_sb->local_nls,
985 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len++; /* trailing null */
987 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700988 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400989 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400991 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
993
994 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000995 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 pSMB->ByteCount = cpu_to_le16(name_len + 1);
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400999 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001000 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001001 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto RmDirRetry;
1006 return rc;
1007}
1008
1009int
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001010CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1011 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
1013 int rc = 0;
1014 CREATE_DIRECTORY_REQ *pSMB = NULL;
1015 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1016 int bytes_returned;
1017 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001018 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Joe Perchesf96637b2013-05-04 22:12:25 -05001020 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021MkDirRetry:
1022 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1023 (void **) &pSMBr);
1024 if (rc)
1025 return rc;
1026
1027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001028 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001029 PATH_MAX, cifs_sb->local_nls,
1030 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 name_len++; /* trailing null */
1032 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001033 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 name_len = strnlen(name, PATH_MAX);
1035 name_len++; /* trailing null */
1036 strncpy(pSMB->DirName, name, name_len);
1037 }
1038
1039 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001040 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001044 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001045 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001046 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 cifs_buf_release(pSMB);
1049 if (rc == -EAGAIN)
1050 goto MkDirRetry;
1051 return rc;
1052}
1053
Steve French2dd29d32007-04-23 22:07:35 +00001054int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001055CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1056 __u32 posix_flags, __u64 mode, __u16 *netfid,
1057 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1058 const char *name, const struct nls_table *nls_codepage,
1059 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001060{
1061 TRANSACTION2_SPI_REQ *pSMB = NULL;
1062 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1063 int name_len;
1064 int rc = 0;
1065 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001066 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001067 OPEN_PSX_REQ *pdata;
1068 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001069
Joe Perchesf96637b2013-05-04 22:12:25 -05001070 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001071PsxCreat:
1072 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1073 (void **) &pSMBr);
1074 if (rc)
1075 return rc;
1076
1077 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1078 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001079 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1080 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001081 name_len++; /* trailing null */
1082 name_len *= 2;
1083 } else { /* BB improve the check for buffer overruns BB */
1084 name_len = strnlen(name, PATH_MAX);
1085 name_len++; /* trailing null */
1086 strncpy(pSMB->FileName, name, name_len);
1087 }
1088
1089 params = 6 + name_len;
1090 count = sizeof(OPEN_PSX_REQ);
1091 pSMB->MaxParameterCount = cpu_to_le16(2);
1092 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1093 pSMB->MaxSetupCount = 0;
1094 pSMB->Reserved = 0;
1095 pSMB->Flags = 0;
1096 pSMB->Timeout = 0;
1097 pSMB->Reserved2 = 0;
1098 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001099 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001100 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001101 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001103 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001104 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001105 pdata->OpenFlags = cpu_to_le32(*pOplock);
1106 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1107 pSMB->DataOffset = cpu_to_le16(offset);
1108 pSMB->SetupCount = 1;
1109 pSMB->Reserved3 = 0;
1110 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1111 byte_count = 3 /* pad */ + params + count;
1112
1113 pSMB->DataCount = cpu_to_le16(count);
1114 pSMB->ParameterCount = cpu_to_le16(params);
1115 pSMB->TotalDataCount = pSMB->DataCount;
1116 pSMB->TotalParameterCount = pSMB->ParameterCount;
1117 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1118 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001119 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001120 pSMB->ByteCount = cpu_to_le16(byte_count);
1121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1123 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001124 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001125 goto psx_create_err;
1126 }
1127
Joe Perchesf96637b2013-05-04 22:12:25 -05001128 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001129 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1130
Jeff Layton820a8032011-05-04 08:05:26 -04001131 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001132 rc = -EIO; /* bad smb */
1133 goto psx_create_err;
1134 }
1135
1136 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001137 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001138 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001139
Steve French2dd29d32007-04-23 22:07:35 +00001140 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001141 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001142 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1143 /* Let caller know file was created so we can set the mode. */
1144 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001145 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001146 *pOplock |= CIFS_CREATE_ACTION;
1147 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001148 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1149 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001150 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001151 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001152 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001153 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001154 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001155 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001156 goto psx_create_err;
1157 }
Steve French50c2f752007-07-13 00:33:32 +00001158 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001159 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001160 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001161 }
Steve French2dd29d32007-04-23 22:07:35 +00001162
1163psx_create_err:
1164 cifs_buf_release(pSMB);
1165
Steve French65bc98b2009-07-10 15:27:25 +00001166 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001167 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001168 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001169 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001170
1171 if (rc == -EAGAIN)
1172 goto PsxCreat;
1173
Steve French50c2f752007-07-13 00:33:32 +00001174 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001175}
1176
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177static __u16 convert_disposition(int disposition)
1178{
1179 __u16 ofun = 0;
1180
1181 switch (disposition) {
1182 case FILE_SUPERSEDE:
1183 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1184 break;
1185 case FILE_OPEN:
1186 ofun = SMBOPEN_OAPPEND;
1187 break;
1188 case FILE_CREATE:
1189 ofun = SMBOPEN_OCREATE;
1190 break;
1191 case FILE_OPEN_IF:
1192 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1193 break;
1194 case FILE_OVERWRITE:
1195 ofun = SMBOPEN_OTRUNC;
1196 break;
1197 case FILE_OVERWRITE_IF:
1198 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1199 break;
1200 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001201 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001202 ofun = SMBOPEN_OAPPEND; /* regular open */
1203 }
1204 return ofun;
1205}
1206
Jeff Layton35fc37d2008-05-14 10:22:03 -07001207static int
1208access_flags_to_smbopen_mode(const int access_flags)
1209{
1210 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1211
1212 if (masked_flags == GENERIC_READ)
1213 return SMBOPEN_READ;
1214 else if (masked_flags == GENERIC_WRITE)
1215 return SMBOPEN_WRITE;
1216
1217 /* just go for read/write */
1218 return SMBOPEN_READWRITE;
1219}
1220
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001222SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 const int access_flags, const int create_options, __u16 *netfid,
1225 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 const struct nls_table *nls_codepage, int remap)
1227{
1228 int rc = -EACCES;
1229 OPENX_REQ *pSMB = NULL;
1230 OPENX_RSP *pSMBr = NULL;
1231 int bytes_returned;
1232 int name_len;
1233 __u16 count;
1234
1235OldOpenRetry:
1236 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1237 (void **) &pSMBr);
1238 if (rc)
1239 return rc;
1240
1241 pSMB->AndXCommand = 0xFF; /* none */
1242
1243 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1244 count = 1; /* account for one byte pad to word boundary */
1245 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001246 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1247 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 name_len++; /* trailing null */
1249 name_len *= 2;
1250 } else { /* BB improve check for buffer overruns BB */
1251 count = 0; /* no pad */
1252 name_len = strnlen(fileName, PATH_MAX);
1253 name_len++; /* trailing null */
1254 strncpy(pSMB->fileName, fileName, name_len);
1255 }
1256 if (*pOplock & REQ_OPLOCK)
1257 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001258 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001260
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001262 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1264 /* set file as system file if special file such
1265 as fifo and server expecting SFU style and
1266 no Unix extensions */
1267
Steve French790fe572007-07-07 19:25:05 +00001268 if (create_options & CREATE_OPTION_SPECIAL)
1269 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001270 else /* BB FIXME BB */
1271 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001272
Jeff Layton67750fb2008-05-09 22:28:02 +00001273 if (create_options & CREATE_OPTION_READONLY)
1274 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275
1276 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001277/* pSMB->CreateOptions = cpu_to_le32(create_options &
1278 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001280
1281 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001282 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001284 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001285
1286 pSMB->ByteCount = cpu_to_le16(count);
1287 /* long_op set to 1 to allow for oplock break timeouts */
1288 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001289 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001290 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001291 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001292 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001293 } else {
1294 /* BB verify if wct == 15 */
1295
Steve French582d21e2008-05-13 04:54:12 +00001296/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297
1298 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1299 /* Let caller know file was created so we can set the mode. */
1300 /* Do we care about the CreateAction in any other cases? */
1301 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001302/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 *pOplock |= CIFS_CREATE_ACTION; */
1304 /* BB FIXME END */
1305
Steve French790fe572007-07-07 19:25:05 +00001306 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001307 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1308 pfile_info->LastAccessTime = 0; /* BB fixme */
1309 pfile_info->LastWriteTime = 0; /* BB fixme */
1310 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001311 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001312 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001313 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001314 pfile_info->AllocationSize =
1315 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1316 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001317 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001318 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001319 }
1320 }
1321
1322 cifs_buf_release(pSMB);
1323 if (rc == -EAGAIN)
1324 goto OldOpenRetry;
1325 return rc;
1326}
1327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001329CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001331 const int access_flags, const int create_options, __u16 *netfid,
1332 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001333 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334{
1335 int rc = -EACCES;
1336 OPEN_REQ *pSMB = NULL;
1337 OPEN_RSP *pSMBr = NULL;
1338 int bytes_returned;
1339 int name_len;
1340 __u16 count;
1341
1342openRetry:
1343 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1344 (void **) &pSMBr);
1345 if (rc)
1346 return rc;
1347
1348 pSMB->AndXCommand = 0xFF; /* none */
1349
1350 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1351 count = 1; /* account for one byte pad to word boundary */
1352 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001353 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1354 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 name_len++; /* trailing null */
1356 name_len *= 2;
1357 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001358 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 count = 0; /* no pad */
1360 name_len = strnlen(fileName, PATH_MAX);
1361 name_len++; /* trailing null */
1362 pSMB->NameLength = cpu_to_le16(name_len);
1363 strncpy(pSMB->fileName, fileName, name_len);
1364 }
1365 if (*pOplock & REQ_OPLOCK)
1366 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001367 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1370 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001371 /* set file as system file if special file such
1372 as fifo and server expecting SFU style and
1373 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001374 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001375 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1376 else
1377 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001378
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 /* XP does not handle ATTR_POSIX_SEMANTICS */
1380 /* but it helps speed up case sensitive checks for other
1381 servers such as Samba */
1382 if (tcon->ses->capabilities & CAP_UNIX)
1383 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1384
Jeff Layton67750fb2008-05-09 22:28:02 +00001385 if (create_options & CREATE_OPTION_READONLY)
1386 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1387
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1389 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001390 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001391 /* BB Expirement with various impersonation levels and verify */
1392 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 pSMB->SecurityFlags =
1394 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1395
1396 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001397 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 pSMB->ByteCount = cpu_to_le16(count);
1400 /* long_op set to 1 to allow for oplock break timeouts */
1401 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001402 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001403 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001405 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 } else {
Steve French09d1db52005-04-28 22:41:08 -07001407 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1409 /* Let caller know file was created so we can set the mode. */
1410 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001411 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001412 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001413 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001414 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1415 36 /* CreationTime to Attributes */);
1416 /* the file_info buf is endian converted by caller */
1417 pfile_info->AllocationSize = pSMBr->AllocationSize;
1418 pfile_info->EndOfFile = pSMBr->EndOfFile;
1419 pfile_info->NumberOfLinks = cpu_to_le32(1);
1420 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 cifs_buf_release(pSMB);
1425 if (rc == -EAGAIN)
1426 goto openRetry;
1427 return rc;
1428}
1429
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001430/*
1431 * Discard any remaining data in the current SMB. To do this, we borrow the
1432 * current bigbuf.
1433 */
1434static int
1435cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1436{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001437 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438 int remaining = rfclen + 4 - server->total_read;
1439 struct cifs_readdata *rdata = mid->callback_data;
1440
1441 while (remaining > 0) {
1442 int length;
1443
1444 length = cifs_read_from_socket(server, server->bigbuf,
1445 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001446 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001447 if (length < 0)
1448 return length;
1449 server->total_read += length;
1450 remaining -= length;
1451 }
1452
1453 dequeue_mid(mid, rdata->result);
1454 return 0;
1455}
1456
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001457int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001458cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1459{
1460 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001461 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001462 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001463 char *buf = server->smallbuf;
1464 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465
Joe Perchesf96637b2013-05-04 22:12:25 -05001466 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1467 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001468
1469 /*
1470 * read the rest of READ_RSP header (sans Data array), or whatever we
1471 * can if there's not enough data. At this point, we've read down to
1472 * the Mid.
1473 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001474 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001475 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476
Jeff Layton58195752012-09-19 06:22:34 -07001477 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1478 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479
Jeff Layton58195752012-09-19 06:22:34 -07001480 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 if (length < 0)
1482 return length;
1483 server->total_read += length;
1484
1485 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001486 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001487 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001488 cifs_dbg(FYI, "%s: server returned error %d\n",
1489 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001490 return cifs_readv_discard(server, mid);
1491 }
1492
1493 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001494 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001495 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1496 __func__, server->total_read,
1497 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001498 rdata->result = -EIO;
1499 return cifs_readv_discard(server, mid);
1500 }
1501
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001502 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001503 if (data_offset < server->total_read) {
1504 /*
1505 * win2k8 sometimes sends an offset of 0 when the read
1506 * is beyond the EOF. Treat it as if the data starts just after
1507 * the header.
1508 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001509 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1510 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001511 data_offset = server->total_read;
1512 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1513 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001514 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1515 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516 rdata->result = -EIO;
1517 return cifs_readv_discard(server, mid);
1518 }
1519
Joe Perchesf96637b2013-05-04 22:12:25 -05001520 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1521 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522
1523 len = data_offset - server->total_read;
1524 if (len > 0) {
1525 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001526 rdata->iov.iov_base = buf + server->total_read;
1527 rdata->iov.iov_len = len;
1528 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529 if (length < 0)
1530 return length;
1531 server->total_read += length;
1532 }
1533
1534 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001535 rdata->iov.iov_base = buf;
1536 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001537 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1538 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001539
1540 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001541 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001542 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543 /* data_len is corrupt -- discard frame */
1544 rdata->result = -EIO;
1545 return cifs_readv_discard(server, mid);
1546 }
1547
Jeff Layton8321fec2012-09-19 06:22:32 -07001548 length = rdata->read_into_pages(server, rdata, data_len);
1549 if (length < 0)
1550 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001551
Jeff Layton8321fec2012-09-19 06:22:32 -07001552 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001553 rdata->bytes = length;
1554
Joe Perchesf96637b2013-05-04 22:12:25 -05001555 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1556 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557
1558 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001559 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560 return cifs_readv_discard(server, mid);
1561
1562 dequeue_mid(mid, false);
1563 return length;
1564}
1565
1566static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001567cifs_readv_callback(struct mid_q_entry *mid)
1568{
1569 struct cifs_readdata *rdata = mid->callback_data;
1570 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1571 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001572 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1573 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001574 .rq_pages = rdata->pages,
1575 .rq_npages = rdata->nr_pages,
1576 .rq_pagesz = rdata->pagesz,
1577 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001578
Joe Perchesf96637b2013-05-04 22:12:25 -05001579 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1580 __func__, mid->mid, mid->mid_state, rdata->result,
1581 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001582
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001583 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001584 case MID_RESPONSE_RECEIVED:
1585 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001586 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001587 int rc = 0;
1588
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001589 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001590 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001591 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001592 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1593 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001594 }
1595 /* FIXME: should this be counted toward the initiating task? */
1596 task_io_account_read(rdata->bytes);
1597 cifs_stats_bytes_read(tcon, rdata->bytes);
1598 break;
1599 case MID_REQUEST_SUBMITTED:
1600 case MID_RETRY_NEEDED:
1601 rdata->result = -EAGAIN;
1602 break;
1603 default:
1604 rdata->result = -EIO;
1605 }
1606
Jeff Laytonda472fc2012-03-23 14:40:53 -04001607 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001609 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001610}
1611
1612/* cifs_async_readv - send an async write, and set up mid to handle result */
1613int
1614cifs_async_readv(struct cifs_readdata *rdata)
1615{
1616 int rc;
1617 READ_REQ *smb = NULL;
1618 int wct;
1619 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001620 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001621 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001622
Joe Perchesf96637b2013-05-04 22:12:25 -05001623 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1624 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625
1626 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1627 wct = 12;
1628 else {
1629 wct = 10; /* old style read */
1630 if ((rdata->offset >> 32) > 0) {
1631 /* can not handle this big offset for old */
1632 return -EIO;
1633 }
1634 }
1635
1636 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1637 if (rc)
1638 return rc;
1639
1640 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1641 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1642
1643 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001644 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001645 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1646 if (wct == 12)
1647 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1648 smb->Remaining = 0;
1649 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1650 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1651 if (wct == 12)
1652 smb->ByteCount = 0;
1653 else {
1654 /* old style read */
1655 struct smb_com_readx_req *smbr =
1656 (struct smb_com_readx_req *)smb;
1657 smbr->ByteCount = 0;
1658 }
1659
1660 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001661 rdata->iov.iov_base = smb;
1662 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001663
Jeff Layton6993f742012-05-16 07:13:17 -04001664 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001665 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1666 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001667
1668 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001669 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001670 else
1671 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001672
1673 cifs_small_buf_release(smb);
1674 return rc;
1675}
1676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001678CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1679 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 int rc = -EACCES;
1682 READ_REQ *pSMB = NULL;
1683 READ_RSP *pSMBr = NULL;
1684 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001685 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001686 int resp_buf_type = 0;
1687 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001688 __u32 pid = io_parms->pid;
1689 __u16 netfid = io_parms->netfid;
1690 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001691 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001692 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Joe Perchesf96637b2013-05-04 22:12:25 -05001694 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001695 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001696 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001697 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001698 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001699 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001700 /* can not handle this big offset for old */
1701 return -EIO;
1702 }
1703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
1705 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001706 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if (rc)
1708 return rc;
1709
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001710 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1711 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 /* tcon and ses pointer are checked in smb_init */
1714 if (tcon->ses->server == NULL)
1715 return -ECONNABORTED;
1716
Steve Frenchec637e32005-12-12 20:53:18 -08001717 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001719 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001720 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001721 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 pSMB->Remaining = 0;
1724 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1725 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001726 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001727 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1728 else {
1729 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001730 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001731 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001732 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001733 }
Steve Frenchec637e32005-12-12 20:53:18 -08001734
1735 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001736 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001737 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001738 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001739 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001740 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001742 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 } else {
1744 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1745 data_length = data_length << 16;
1746 data_length += le16_to_cpu(pSMBr->DataLength);
1747 *nbytes = data_length;
1748
1749 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001750 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001752 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001753 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 rc = -EIO;
1755 *nbytes = 0;
1756 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001757 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001758 le16_to_cpu(pSMBr->DataOffset);
1759/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001760 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001761 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001762 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001763 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001764 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 }
1766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
Steve French4b8f9302006-02-26 16:41:18 +00001768/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001769 if (*buf) {
1770 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001771 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001772 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001773 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001774 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001775 /* return buffer to caller to free */
1776 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001777 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001778 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001779 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001780 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001781 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001782
1783 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 since file handle passed in no longer valid */
1785 return rc;
1786}
1787
Steve Frenchec637e32005-12-12 20:53:18 -08001788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001790CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001791 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001792 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793{
1794 int rc = -EACCES;
1795 WRITE_REQ *pSMB = NULL;
1796 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001797 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 __u32 bytes_sent;
1799 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001800 __u32 pid = io_parms->pid;
1801 __u16 netfid = io_parms->netfid;
1802 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001803 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001804 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Steve Frencha24e2d72010-04-03 17:20:21 +00001806 *nbytes = 0;
1807
Joe Perchesf96637b2013-05-04 22:12:25 -05001808 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001809 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001810 return -ECONNABORTED;
1811
Steve French790fe572007-07-07 19:25:05 +00001812 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001813 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001814 else {
Steve French1c955182005-08-30 20:58:07 -07001815 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001816 if ((offset >> 32) > 0) {
1817 /* can not handle big offset for old srv */
1818 return -EIO;
1819 }
1820 }
Steve French1c955182005-08-30 20:58:07 -07001821
1822 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 (void **) &pSMBr);
1824 if (rc)
1825 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001826
1827 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1828 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 /* tcon and ses pointer are checked in smb_init */
1831 if (tcon->ses->server == NULL)
1832 return -ECONNABORTED;
1833
1834 pSMB->AndXCommand = 0xFF; /* none */
1835 pSMB->Fid = netfid;
1836 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001837 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001838 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 pSMB->Reserved = 0xFFFFFFFF;
1841 pSMB->WriteMode = 0;
1842 pSMB->Remaining = 0;
1843
Steve French50c2f752007-07-13 00:33:32 +00001844 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 can send more if LARGE_WRITE_X capability returned by the server and if
1846 our buffer is big enough or if we convert to iovecs on socket writes
1847 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001848 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1850 } else {
1851 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1852 & ~0xFF;
1853 }
1854
1855 if (bytes_sent > count)
1856 bytes_sent = count;
1857 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001858 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001859 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001860 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001861 else if (ubuf) {
1862 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 cifs_buf_release(pSMB);
1864 return -EFAULT;
1865 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001866 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 /* No buffer */
1868 cifs_buf_release(pSMB);
1869 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001870 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001871 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001872 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001873 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001874 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1877 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001878 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001879
Steve French790fe572007-07-07 19:25:05 +00001880 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001881 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001882 else { /* old style write has byte count 4 bytes earlier
1883 so 4 bytes pad */
1884 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001885 (struct smb_com_writex_req *)pSMB;
1886 pSMBW->ByteCount = cpu_to_le16(byte_count);
1887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1890 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001891 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001893 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 } else {
1895 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1896 *nbytes = (*nbytes) << 16;
1897 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301898
1899 /*
1900 * Mask off high 16 bits when bytes written as returned by the
1901 * server is greater than bytes requested by the client. Some
1902 * OS/2 servers are known to set incorrect CountHigh values.
1903 */
1904 if (*nbytes > count)
1905 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907
1908 cifs_buf_release(pSMB);
1909
Steve French50c2f752007-07-13 00:33:32 +00001910 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 since file handle passed in no longer valid */
1912
1913 return rc;
1914}
1915
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001916void
1917cifs_writedata_release(struct kref *refcount)
1918{
1919 struct cifs_writedata *wdata = container_of(refcount,
1920 struct cifs_writedata, refcount);
1921
1922 if (wdata->cfile)
1923 cifsFileInfo_put(wdata->cfile);
1924
1925 kfree(wdata);
1926}
1927
1928/*
1929 * Write failed with a retryable error. Resend the write request. It's also
1930 * possible that the page was redirtied so re-clean the page.
1931 */
1932static void
1933cifs_writev_requeue(struct cifs_writedata *wdata)
1934{
1935 int i, rc;
1936 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001937 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001938
1939 for (i = 0; i < wdata->nr_pages; i++) {
1940 lock_page(wdata->pages[i]);
1941 clear_page_dirty_for_io(wdata->pages[i]);
1942 }
1943
1944 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001945 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1946 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001947 } while (rc == -EAGAIN);
1948
1949 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001950 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001951 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001952 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001953 end_page_writeback(wdata->pages[i]);
1954 page_cache_release(wdata->pages[i]);
1955 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001956 }
1957
1958 mapping_set_error(inode->i_mapping, rc);
1959 kref_put(&wdata->refcount, cifs_writedata_release);
1960}
1961
Jeff Laytonc2e87642012-03-23 14:40:55 -04001962void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001963cifs_writev_complete(struct work_struct *work)
1964{
1965 struct cifs_writedata *wdata = container_of(work,
1966 struct cifs_writedata, work);
1967 struct inode *inode = wdata->cfile->dentry->d_inode;
1968 int i = 0;
1969
1970 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001971 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001972 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001973 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001974 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1975 wdata->bytes);
1976 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1977 return cifs_writev_requeue(wdata);
1978
1979 for (i = 0; i < wdata->nr_pages; i++) {
1980 struct page *page = wdata->pages[i];
1981 if (wdata->result == -EAGAIN)
1982 __set_page_dirty_nobuffers(page);
1983 else if (wdata->result < 0)
1984 SetPageError(page);
1985 end_page_writeback(page);
1986 page_cache_release(page);
1987 }
1988 if (wdata->result != -EAGAIN)
1989 mapping_set_error(inode->i_mapping, wdata->result);
1990 kref_put(&wdata->refcount, cifs_writedata_release);
1991}
1992
1993struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001994cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001995{
1996 struct cifs_writedata *wdata;
1997
1998 /* this would overflow */
1999 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002000 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002001 return NULL;
2002 }
2003
2004 /* writedata + number of page pointers */
2005 wdata = kzalloc(sizeof(*wdata) +
2006 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
2007 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002008 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002009 INIT_LIST_HEAD(&wdata->list);
2010 init_completion(&wdata->done);
2011 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002012 }
2013 return wdata;
2014}
2015
2016/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002017 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002018 * workqueue completion task.
2019 */
2020static void
2021cifs_writev_callback(struct mid_q_entry *mid)
2022{
2023 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002024 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002025 unsigned int written;
2026 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2027
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002028 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002029 case MID_RESPONSE_RECEIVED:
2030 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2031 if (wdata->result != 0)
2032 break;
2033
2034 written = le16_to_cpu(smb->CountHigh);
2035 written <<= 16;
2036 written += le16_to_cpu(smb->Count);
2037 /*
2038 * Mask off high 16 bits when bytes written as returned
2039 * by the server is greater than bytes requested by the
2040 * client. OS/2 servers are known to set incorrect
2041 * CountHigh values.
2042 */
2043 if (written > wdata->bytes)
2044 written &= 0xFFFF;
2045
2046 if (written < wdata->bytes)
2047 wdata->result = -ENOSPC;
2048 else
2049 wdata->bytes = written;
2050 break;
2051 case MID_REQUEST_SUBMITTED:
2052 case MID_RETRY_NEEDED:
2053 wdata->result = -EAGAIN;
2054 break;
2055 default:
2056 wdata->result = -EIO;
2057 break;
2058 }
2059
Jeff Laytonda472fc2012-03-23 14:40:53 -04002060 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002061 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002062 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002063}
2064
2065/* cifs_async_writev - send an async write, and set up mid to handle result */
2066int
2067cifs_async_writev(struct cifs_writedata *wdata)
2068{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002069 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070 WRITE_REQ *smb = NULL;
2071 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002072 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002073 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002074 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002075
2076 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2077 wct = 14;
2078 } else {
2079 wct = 12;
2080 if (wdata->offset >> 32 > 0) {
2081 /* can not handle big offset for old srv */
2082 return -EIO;
2083 }
2084 }
2085
2086 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2087 if (rc)
2088 goto async_writev_out;
2089
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002090 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2091 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002092
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002093 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002094 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2096 if (wct == 14)
2097 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2098 smb->Reserved = 0xFFFFFFFF;
2099 smb->WriteMode = 0;
2100 smb->Remaining = 0;
2101
2102 smb->DataOffset =
2103 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2104
2105 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002106 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2107 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002108
Jeff Laytoneddb0792012-09-18 16:20:35 -07002109 rqst.rq_iov = &iov;
2110 rqst.rq_nvec = 1;
2111 rqst.rq_pages = wdata->pages;
2112 rqst.rq_npages = wdata->nr_pages;
2113 rqst.rq_pagesz = wdata->pagesz;
2114 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002115
Joe Perchesf96637b2013-05-04 22:12:25 -05002116 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2117 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002118
2119 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2120 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2121
2122 if (wct == 14) {
2123 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2124 put_bcc(wdata->bytes + 1, &smb->hdr);
2125 } else {
2126 /* wct == 12 */
2127 struct smb_com_writex_req *smbw =
2128 (struct smb_com_writex_req *)smb;
2129 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2130 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002131 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002132 }
2133
2134 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002135 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2136 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002137
2138 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002139 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002140 else
2141 kref_put(&wdata->refcount, cifs_writedata_release);
2142
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002143async_writev_out:
2144 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002145 return rc;
2146}
2147
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002148int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002149CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002150 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151{
2152 int rc = -EACCES;
2153 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002154 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002155 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002156 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002157 __u32 pid = io_parms->pid;
2158 __u16 netfid = io_parms->netfid;
2159 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002160 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002161 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002163 *nbytes = 0;
2164
Joe Perchesf96637b2013-05-04 22:12:25 -05002165 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002166
Steve French4c3130e2008-12-09 00:28:16 +00002167 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002168 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002169 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002170 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002171 if ((offset >> 32) > 0) {
2172 /* can not handle big offset for old srv */
2173 return -EIO;
2174 }
2175 }
Steve French8cc64c62005-10-03 13:49:43 -07002176 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 if (rc)
2178 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002179
2180 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2181 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2182
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 /* tcon and ses pointer are checked in smb_init */
2184 if (tcon->ses->server == NULL)
2185 return -ECONNABORTED;
2186
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002187 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 pSMB->Fid = netfid;
2189 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002190 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002191 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 pSMB->Reserved = 0xFFFFFFFF;
2193 pSMB->WriteMode = 0;
2194 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002195
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002197 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Steve French3e844692005-10-03 13:37:24 -07002199 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2200 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002201 /* header + 1 byte pad */
2202 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002203 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002204 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002205 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002206 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002207 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002208 pSMB->ByteCount = cpu_to_le16(count + 1);
2209 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002210 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002211 (struct smb_com_writex_req *)pSMB;
2212 pSMBW->ByteCount = cpu_to_le16(count + 5);
2213 }
Steve French3e844692005-10-03 13:37:24 -07002214 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002215 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002216 iov[0].iov_len = smb_hdr_len + 4;
2217 else /* wct == 12 pad bigger by four bytes */
2218 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002219
Steve French3e844692005-10-03 13:37:24 -07002220
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002221 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002222 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002224 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002225 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002226 /* presumably this can not happen, but best to be safe */
2227 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002228 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002229 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002230 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2231 *nbytes = (*nbytes) << 16;
2232 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302233
2234 /*
2235 * Mask off high 16 bits when bytes written as returned by the
2236 * server is greater than bytes requested by the client. OS/2
2237 * servers are known to set incorrect CountHigh values.
2238 */
2239 if (*nbytes > count)
2240 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Steve French4b8f9302006-02-26 16:41:18 +00002243/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002244 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002245 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002246 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002247 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
Steve French50c2f752007-07-13 00:33:32 +00002249 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 since file handle passed in no longer valid */
2251
2252 return rc;
2253}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002254
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002255int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2256 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002257 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2258{
2259 int rc = 0;
2260 LOCK_REQ *pSMB = NULL;
2261 struct kvec iov[2];
2262 int resp_buf_type;
2263 __u16 count;
2264
Joe Perchesf96637b2013-05-04 22:12:25 -05002265 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2266 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002267
2268 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2269 if (rc)
2270 return rc;
2271
2272 pSMB->Timeout = 0;
2273 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2274 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2275 pSMB->LockType = lock_type;
2276 pSMB->AndXCommand = 0xFF; /* none */
2277 pSMB->Fid = netfid; /* netfid stays le */
2278
2279 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2280 inc_rfc1001_len(pSMB, count);
2281 pSMB->ByteCount = cpu_to_le16(count);
2282
2283 iov[0].iov_base = (char *)pSMB;
2284 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2285 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2286 iov[1].iov_base = (char *)buf;
2287 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2288
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002289 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002290 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2291 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002292 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002293
2294 return rc;
2295}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002298CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002299 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002301 const __u32 numLock, const __u8 lockType,
2302 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303{
2304 int rc = 0;
2305 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002306/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002308 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 __u16 count;
2310
Joe Perchesf96637b2013-05-04 22:12:25 -05002311 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2312 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002313 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2314
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 if (rc)
2316 return rc;
2317
Steve French790fe572007-07-07 19:25:05 +00002318 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002319 /* no response expected */
2320 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002322 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002323 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2325 } else {
2326 pSMB->Timeout = 0;
2327 }
2328
2329 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2330 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2331 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002332 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 pSMB->AndXCommand = 0xFF; /* none */
2334 pSMB->Fid = smb_file_id; /* netfid stays le */
2335
Steve French790fe572007-07-07 19:25:05 +00002336 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002337 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 /* BB where to store pid high? */
2339 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2340 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2341 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2342 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2343 count = sizeof(LOCKING_ANDX_RANGE);
2344 } else {
2345 /* oplock break */
2346 count = 0;
2347 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002348 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 pSMB->ByteCount = cpu_to_le16(count);
2350
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002351 if (waitFlag) {
2352 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002353 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002354 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002355 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002356 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002357 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002358 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002359 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002360 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002361 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362
Steve French50c2f752007-07-13 00:33:32 +00002363 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 since file handle passed in no longer valid */
2365 return rc;
2366}
2367
2368int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002369CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002370 const __u16 smb_file_id, const __u32 netpid,
2371 const loff_t start_offset, const __u64 len,
2372 struct file_lock *pLockData, const __u16 lock_type,
2373 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002374{
2375 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2376 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002377 struct cifs_posix_lock *parm_data;
2378 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002379 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002380 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002381 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002382 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002383 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002384
Joe Perchesf96637b2013-05-04 22:12:25 -05002385 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002386
Steve French08547b02006-02-28 22:39:25 +00002387 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2388
2389 if (rc)
2390 return rc;
2391
2392 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2393
Steve French50c2f752007-07-13 00:33:32 +00002394 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002395 pSMB->MaxSetupCount = 0;
2396 pSMB->Reserved = 0;
2397 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002398 pSMB->Reserved2 = 0;
2399 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2400 offset = param_offset + params;
2401
Steve French08547b02006-02-28 22:39:25 +00002402 count = sizeof(struct cifs_posix_lock);
2403 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002404 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002405 pSMB->SetupCount = 1;
2406 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002407 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002408 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2409 else
2410 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2411 byte_count = 3 /* pad */ + params + count;
2412 pSMB->DataCount = cpu_to_le16(count);
2413 pSMB->ParameterCount = cpu_to_le16(params);
2414 pSMB->TotalDataCount = pSMB->DataCount;
2415 pSMB->TotalParameterCount = pSMB->ParameterCount;
2416 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002417 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002418 (((char *) &pSMB->hdr.Protocol) + offset);
2419
2420 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002421 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002422 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002423 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002424 pSMB->Timeout = cpu_to_le32(-1);
2425 } else
2426 pSMB->Timeout = 0;
2427
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002428 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002429 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002430 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002431
2432 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002433 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002434 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2435 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002436 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002437 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002438 if (waitFlag) {
2439 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2440 (struct smb_hdr *) pSMBr, &bytes_returned);
2441 } else {
Steve French133672e2007-11-13 22:41:37 +00002442 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002443 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002444 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2445 &resp_buf_type, timeout);
2446 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2447 not try to free it twice below on exit */
2448 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002449 }
2450
Steve French08547b02006-02-28 22:39:25 +00002451 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002452 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002453 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002454 /* lock structure can be returned on get */
2455 __u16 data_offset;
2456 __u16 data_count;
2457 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002458
Jeff Layton820a8032011-05-04 08:05:26 -04002459 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002460 rc = -EIO; /* bad smb */
2461 goto plk_err_exit;
2462 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002463 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2464 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002465 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002466 rc = -EIO;
2467 goto plk_err_exit;
2468 }
2469 parm_data = (struct cifs_posix_lock *)
2470 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002471 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002472 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002473 else {
2474 if (parm_data->lock_type ==
2475 __constant_cpu_to_le16(CIFS_RDLCK))
2476 pLockData->fl_type = F_RDLCK;
2477 else if (parm_data->lock_type ==
2478 __constant_cpu_to_le16(CIFS_WRLCK))
2479 pLockData->fl_type = F_WRLCK;
2480
Steve French5443d132011-03-13 05:08:25 +00002481 pLockData->fl_start = le64_to_cpu(parm_data->start);
2482 pLockData->fl_end = pLockData->fl_start +
2483 le64_to_cpu(parm_data->length) - 1;
2484 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002485 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002486 }
Steve French50c2f752007-07-13 00:33:32 +00002487
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002488plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002489 if (pSMB)
2490 cifs_small_buf_release(pSMB);
2491
Steve French133672e2007-11-13 22:41:37 +00002492 if (resp_buf_type == CIFS_SMALL_BUFFER)
2493 cifs_small_buf_release(iov[0].iov_base);
2494 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2495 cifs_buf_release(iov[0].iov_base);
2496
Steve French08547b02006-02-28 22:39:25 +00002497 /* Note: On -EAGAIN error only caller can retry on handle based calls
2498 since file handle passed in no longer valid */
2499
2500 return rc;
2501}
2502
2503
2504int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002505CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506{
2507 int rc = 0;
2508 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002509 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511/* do not retry on dead session on close */
2512 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002513 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 return 0;
2515 if (rc)
2516 return rc;
2517
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002519 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002521 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002522 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002524 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002526 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 }
2528 }
2529
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002531 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 rc = 0;
2533
2534 return rc;
2535}
2536
2537int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002538CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002539{
2540 int rc = 0;
2541 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002542 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002543
2544 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2545 if (rc)
2546 return rc;
2547
2548 pSMB->FileID = (__u16) smb_file_id;
2549 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002550 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002551 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002552 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002553 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002554
2555 return rc;
2556}
2557
2558int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002559CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002560 const char *from_name, const char *to_name,
2561 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562{
2563 int rc = 0;
2564 RENAME_REQ *pSMB = NULL;
2565 RENAME_RSP *pSMBr = NULL;
2566 int bytes_returned;
2567 int name_len, name_len2;
2568 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002569 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570
Joe Perchesf96637b2013-05-04 22:12:25 -05002571 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572renameRetry:
2573 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2574 (void **) &pSMBr);
2575 if (rc)
2576 return rc;
2577
2578 pSMB->BufferFormat = 0x04;
2579 pSMB->SearchAttributes =
2580 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2581 ATTR_DIRECTORY);
2582
2583 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002584 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2585 from_name, PATH_MAX,
2586 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 name_len++; /* trailing null */
2588 name_len *= 2;
2589 pSMB->OldFileName[name_len] = 0x04; /* pad */
2590 /* protocol requires ASCII signature byte on Unicode string */
2591 pSMB->OldFileName[name_len + 1] = 0x00;
2592 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002593 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002594 to_name, PATH_MAX, cifs_sb->local_nls,
2595 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2597 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002598 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002599 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002601 strncpy(pSMB->OldFileName, from_name, name_len);
2602 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 name_len2++; /* trailing null */
2604 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002605 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 name_len2++; /* trailing null */
2607 name_len2++; /* signature byte */
2608 }
2609
2610 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002611 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 pSMB->ByteCount = cpu_to_le16(count);
2613
2614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002616 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002617 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002618 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 cifs_buf_release(pSMB);
2621
2622 if (rc == -EAGAIN)
2623 goto renameRetry;
2624
2625 return rc;
2626}
2627
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002628int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002629 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002630 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631{
2632 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2633 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002634 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 char *data_offset;
2636 char dummy_string[30];
2637 int rc = 0;
2638 int bytes_returned = 0;
2639 int len_of_str;
2640 __u16 params, param_offset, offset, count, byte_count;
2641
Joe Perchesf96637b2013-05-04 22:12:25 -05002642 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2644 (void **) &pSMBr);
2645 if (rc)
2646 return rc;
2647
2648 params = 6;
2649 pSMB->MaxSetupCount = 0;
2650 pSMB->Reserved = 0;
2651 pSMB->Flags = 0;
2652 pSMB->Timeout = 0;
2653 pSMB->Reserved2 = 0;
2654 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2655 offset = param_offset + params;
2656
2657 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2658 rename_info = (struct set_file_rename *) data_offset;
2659 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002660 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 pSMB->SetupCount = 1;
2662 pSMB->Reserved3 = 0;
2663 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2664 byte_count = 3 /* pad */ + params;
2665 pSMB->ParameterCount = cpu_to_le16(params);
2666 pSMB->TotalParameterCount = pSMB->ParameterCount;
2667 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2668 pSMB->DataOffset = cpu_to_le16(offset);
2669 /* construct random name ".cifs_tmp<inodenum><mid>" */
2670 rename_info->overwrite = cpu_to_le32(1);
2671 rename_info->root_fid = 0;
2672 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002673 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002674 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002675 len_of_str =
2676 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002677 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002679 len_of_str =
2680 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002681 target_name, PATH_MAX, nls_codepage,
2682 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 }
2684 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002685 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 byte_count += count;
2687 pSMB->DataCount = cpu_to_le16(count);
2688 pSMB->TotalDataCount = pSMB->DataCount;
2689 pSMB->Fid = netfid;
2690 pSMB->InformationLevel =
2691 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2692 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002693 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 pSMB->ByteCount = cpu_to_le16(byte_count);
2695 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002696 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002697 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002698 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002699 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2700 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 cifs_buf_release(pSMB);
2703
2704 /* Note: On -EAGAIN error only caller can retry on handle based calls
2705 since file handle passed in no longer valid */
2706
2707 return rc;
2708}
2709
2710int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002711CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2712 const char *fromName, const __u16 target_tid, const char *toName,
2713 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714{
2715 int rc = 0;
2716 COPY_REQ *pSMB = NULL;
2717 COPY_RSP *pSMBr = NULL;
2718 int bytes_returned;
2719 int name_len, name_len2;
2720 __u16 count;
2721
Joe Perchesf96637b2013-05-04 22:12:25 -05002722 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723copyRetry:
2724 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2725 (void **) &pSMBr);
2726 if (rc)
2727 return rc;
2728
2729 pSMB->BufferFormat = 0x04;
2730 pSMB->Tid2 = target_tid;
2731
2732 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2733
2734 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002735 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2736 fromName, PATH_MAX, nls_codepage,
2737 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 name_len++; /* trailing null */
2739 name_len *= 2;
2740 pSMB->OldFileName[name_len] = 0x04; /* pad */
2741 /* protocol requires ASCII signature byte on Unicode string */
2742 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002743 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002744 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2745 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2747 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002748 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 name_len = strnlen(fromName, PATH_MAX);
2750 name_len++; /* trailing null */
2751 strncpy(pSMB->OldFileName, fromName, name_len);
2752 name_len2 = strnlen(toName, PATH_MAX);
2753 name_len2++; /* trailing null */
2754 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2755 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2756 name_len2++; /* trailing null */
2757 name_len2++; /* signature byte */
2758 }
2759
2760 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002761 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 pSMB->ByteCount = cpu_to_le16(count);
2763
2764 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2765 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2766 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002767 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2768 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 }
Steve French0d817bc2008-05-22 02:02:03 +00002770 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771
2772 if (rc == -EAGAIN)
2773 goto copyRetry;
2774
2775 return rc;
2776}
2777
2778int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002779CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 const char *fromName, const char *toName,
2781 const struct nls_table *nls_codepage)
2782{
2783 TRANSACTION2_SPI_REQ *pSMB = NULL;
2784 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2785 char *data_offset;
2786 int name_len;
2787 int name_len_target;
2788 int rc = 0;
2789 int bytes_returned = 0;
2790 __u16 params, param_offset, offset, byte_count;
2791
Joe Perchesf96637b2013-05-04 22:12:25 -05002792 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793createSymLinkRetry:
2794 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2795 (void **) &pSMBr);
2796 if (rc)
2797 return rc;
2798
2799 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2800 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002801 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2802 /* find define for this maxpathcomponent */
2803 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 name_len++; /* trailing null */
2805 name_len *= 2;
2806
Steve French50c2f752007-07-13 00:33:32 +00002807 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 name_len = strnlen(fromName, PATH_MAX);
2809 name_len++; /* trailing null */
2810 strncpy(pSMB->FileName, fromName, name_len);
2811 }
2812 params = 6 + name_len;
2813 pSMB->MaxSetupCount = 0;
2814 pSMB->Reserved = 0;
2815 pSMB->Flags = 0;
2816 pSMB->Timeout = 0;
2817 pSMB->Reserved2 = 0;
2818 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002819 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 offset = param_offset + params;
2821
2822 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2823 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2824 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002825 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2826 /* find define for this maxpathcomponent */
2827 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 name_len_target++; /* trailing null */
2829 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002830 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 name_len_target = strnlen(toName, PATH_MAX);
2832 name_len_target++; /* trailing null */
2833 strncpy(data_offset, toName, name_len_target);
2834 }
2835
2836 pSMB->MaxParameterCount = cpu_to_le16(2);
2837 /* BB find exact max on data count below from sess */
2838 pSMB->MaxDataCount = cpu_to_le16(1000);
2839 pSMB->SetupCount = 1;
2840 pSMB->Reserved3 = 0;
2841 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2842 byte_count = 3 /* pad */ + params + name_len_target;
2843 pSMB->DataCount = cpu_to_le16(name_len_target);
2844 pSMB->ParameterCount = cpu_to_le16(params);
2845 pSMB->TotalDataCount = pSMB->DataCount;
2846 pSMB->TotalParameterCount = pSMB->ParameterCount;
2847 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2848 pSMB->DataOffset = cpu_to_le16(offset);
2849 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2850 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002851 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 pSMB->ByteCount = cpu_to_le16(byte_count);
2853 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2854 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002855 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002856 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002857 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2858 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
Steve French0d817bc2008-05-22 02:02:03 +00002860 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 if (rc == -EAGAIN)
2863 goto createSymLinkRetry;
2864
2865 return rc;
2866}
2867
2868int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002869CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002871 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872{
2873 TRANSACTION2_SPI_REQ *pSMB = NULL;
2874 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2875 char *data_offset;
2876 int name_len;
2877 int name_len_target;
2878 int rc = 0;
2879 int bytes_returned = 0;
2880 __u16 params, param_offset, offset, byte_count;
2881
Joe Perchesf96637b2013-05-04 22:12:25 -05002882 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883createHardLinkRetry:
2884 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2885 (void **) &pSMBr);
2886 if (rc)
2887 return rc;
2888
2889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002890 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2891 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 name_len++; /* trailing null */
2893 name_len *= 2;
2894
Steve French50c2f752007-07-13 00:33:32 +00002895 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 name_len = strnlen(toName, PATH_MAX);
2897 name_len++; /* trailing null */
2898 strncpy(pSMB->FileName, toName, name_len);
2899 }
2900 params = 6 + name_len;
2901 pSMB->MaxSetupCount = 0;
2902 pSMB->Reserved = 0;
2903 pSMB->Flags = 0;
2904 pSMB->Timeout = 0;
2905 pSMB->Reserved2 = 0;
2906 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002907 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 offset = param_offset + params;
2909
2910 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2911 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2912 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002913 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2914 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 name_len_target++; /* trailing null */
2916 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002917 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 name_len_target = strnlen(fromName, PATH_MAX);
2919 name_len_target++; /* trailing null */
2920 strncpy(data_offset, fromName, name_len_target);
2921 }
2922
2923 pSMB->MaxParameterCount = cpu_to_le16(2);
2924 /* BB find exact max on data count below from sess*/
2925 pSMB->MaxDataCount = cpu_to_le16(1000);
2926 pSMB->SetupCount = 1;
2927 pSMB->Reserved3 = 0;
2928 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2929 byte_count = 3 /* pad */ + params + name_len_target;
2930 pSMB->ParameterCount = cpu_to_le16(params);
2931 pSMB->TotalParameterCount = pSMB->ParameterCount;
2932 pSMB->DataCount = cpu_to_le16(name_len_target);
2933 pSMB->TotalDataCount = pSMB->DataCount;
2934 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2935 pSMB->DataOffset = cpu_to_le16(offset);
2936 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2937 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002938 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 pSMB->ByteCount = cpu_to_le16(byte_count);
2940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2941 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002942 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002943 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002944 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2945 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
2947 cifs_buf_release(pSMB);
2948 if (rc == -EAGAIN)
2949 goto createHardLinkRetry;
2950
2951 return rc;
2952}
2953
2954int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002955CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002956 const char *from_name, const char *to_name,
2957 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958{
2959 int rc = 0;
2960 NT_RENAME_REQ *pSMB = NULL;
2961 RENAME_RSP *pSMBr = NULL;
2962 int bytes_returned;
2963 int name_len, name_len2;
2964 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002965 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
Joe Perchesf96637b2013-05-04 22:12:25 -05002967 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968winCreateHardLinkRetry:
2969
2970 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2971 (void **) &pSMBr);
2972 if (rc)
2973 return rc;
2974
2975 pSMB->SearchAttributes =
2976 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2977 ATTR_DIRECTORY);
2978 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2979 pSMB->ClusterCount = 0;
2980
2981 pSMB->BufferFormat = 0x04;
2982
2983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2984 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002985 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2986 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 name_len++; /* trailing null */
2988 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002989
2990 /* protocol specifies ASCII buffer format (0x04) for unicode */
2991 pSMB->OldFileName[name_len] = 0x04;
2992 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002994 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002995 to_name, PATH_MAX, cifs_sb->local_nls,
2996 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2998 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002999 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003000 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003002 strncpy(pSMB->OldFileName, from_name, name_len);
3003 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 name_len2++; /* trailing null */
3005 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003006 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 name_len2++; /* trailing null */
3008 name_len2++; /* signature byte */
3009 }
3010
3011 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003012 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 pSMB->ByteCount = cpu_to_le16(count);
3014
3015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003017 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003018 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003019 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003020
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 cifs_buf_release(pSMB);
3022 if (rc == -EAGAIN)
3023 goto winCreateHardLinkRetry;
3024
3025 return rc;
3026}
3027
3028int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003029CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003030 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 const struct nls_table *nls_codepage)
3032{
3033/* SMB_QUERY_FILE_UNIX_LINK */
3034 TRANSACTION2_QPI_REQ *pSMB = NULL;
3035 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3036 int rc = 0;
3037 int bytes_returned;
3038 int name_len;
3039 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003040 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Joe Perchesf96637b2013-05-04 22:12:25 -05003042 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
3044querySymLinkRetry:
3045 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3046 (void **) &pSMBr);
3047 if (rc)
3048 return rc;
3049
3050 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3051 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003052 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3053 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 name_len++; /* trailing null */
3055 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003056 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 name_len = strnlen(searchName, PATH_MAX);
3058 name_len++; /* trailing null */
3059 strncpy(pSMB->FileName, searchName, name_len);
3060 }
3061
3062 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3063 pSMB->TotalDataCount = 0;
3064 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003065 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 pSMB->MaxSetupCount = 0;
3067 pSMB->Reserved = 0;
3068 pSMB->Flags = 0;
3069 pSMB->Timeout = 0;
3070 pSMB->Reserved2 = 0;
3071 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003072 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 pSMB->DataCount = 0;
3074 pSMB->DataOffset = 0;
3075 pSMB->SetupCount = 1;
3076 pSMB->Reserved3 = 0;
3077 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3078 byte_count = params + 1 /* pad */ ;
3079 pSMB->TotalParameterCount = cpu_to_le16(params);
3080 pSMB->ParameterCount = pSMB->TotalParameterCount;
3081 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3082 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003083 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 pSMB->ByteCount = cpu_to_le16(byte_count);
3085
3086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3088 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003089 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 } else {
3091 /* decode response */
3092
3093 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003095 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003096 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003098 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003099 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Jeff Layton460b9692009-04-30 07:17:56 -04003101 data_start = ((char *) &pSMBr->hdr.Protocol) +
3102 le16_to_cpu(pSMBr->t2.DataOffset);
3103
Steve French0e0d2cf2009-05-01 05:27:32 +00003104 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3105 is_unicode = true;
3106 else
3107 is_unicode = false;
3108
Steve French737b7582005-04-28 22:41:06 -07003109 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003110 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3111 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003112 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003113 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 }
3115 }
3116 cifs_buf_release(pSMB);
3117 if (rc == -EAGAIN)
3118 goto querySymLinkRetry;
3119 return rc;
3120}
3121
Steve Frenchc52a95542011-02-24 06:16:22 +00003122#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3123/*
3124 * Recent Windows versions now create symlinks more frequently
3125 * and they use the "reparse point" mechanism below. We can of course
3126 * do symlinks nicely to Samba and other servers which support the
3127 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3128 * "MF" symlinks optionally, but for recent Windows we really need to
3129 * reenable the code below and fix the cifs_symlink callers to handle this.
3130 * In the interim this code has been moved to its own config option so
3131 * it is not compiled in by default until callers fixed up and more tested.
3132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003134CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003136 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 const struct nls_table *nls_codepage)
3138{
3139 int rc = 0;
3140 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003141 struct smb_com_transaction_ioctl_req *pSMB;
3142 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
Joe Perchesf96637b2013-05-04 22:12:25 -05003144 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3145 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3147 (void **) &pSMBr);
3148 if (rc)
3149 return rc;
3150
3151 pSMB->TotalParameterCount = 0 ;
3152 pSMB->TotalDataCount = 0;
3153 pSMB->MaxParameterCount = cpu_to_le32(2);
3154 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003155 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 pSMB->MaxSetupCount = 4;
3157 pSMB->Reserved = 0;
3158 pSMB->ParameterOffset = 0;
3159 pSMB->DataCount = 0;
3160 pSMB->DataOffset = 0;
3161 pSMB->SetupCount = 4;
3162 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3163 pSMB->ParameterCount = pSMB->TotalParameterCount;
3164 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3165 pSMB->IsFsctl = 1; /* FSCTL */
3166 pSMB->IsRootFlag = 0;
3167 pSMB->Fid = fid; /* file handle always le */
3168 pSMB->ByteCount = 0;
3169
3170 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3171 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3172 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003173 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 } else { /* decode response */
3175 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3176 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003177 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3178 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003180 goto qreparse_out;
3181 }
3182 if (data_count && (data_count < 2048)) {
3183 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003184 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Steve Frenchafe48c32009-05-02 05:25:46 +00003186 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003187 (struct reparse_data *)
3188 ((char *)&pSMBr->hdr.Protocol
3189 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003190 if ((char *)reparse_buf >= end_of_smb) {
3191 rc = -EIO;
3192 goto qreparse_out;
3193 }
3194 if ((reparse_buf->LinkNamesBuf +
3195 reparse_buf->TargetNameOffset +
3196 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003197 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003198 rc = -EIO;
3199 goto qreparse_out;
3200 }
Steve French50c2f752007-07-13 00:33:32 +00003201
Steve Frenchafe48c32009-05-02 05:25:46 +00003202 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3203 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003204 (reparse_buf->LinkNamesBuf +
3205 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003206 buflen,
3207 reparse_buf->TargetNameLen,
3208 nls_codepage, 0);
3209 } else { /* ASCII names */
3210 strncpy(symlinkinfo,
3211 reparse_buf->LinkNamesBuf +
3212 reparse_buf->TargetNameOffset,
3213 min_t(const int, buflen,
3214 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003216 } else {
3217 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003218 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003220 symlinkinfo[buflen] = 0; /* just in case so the caller
3221 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003222 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 }
Steve French989c7e52009-05-02 05:32:20 +00003224
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003226 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
3228 /* Note: On -EAGAIN error only caller can retry on handle based calls
3229 since file handle passed in no longer valid */
3230
3231 return rc;
3232}
Steve Frenchc52a95542011-02-24 06:16:22 +00003233#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
3235#ifdef CONFIG_CIFS_POSIX
3236
3237/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003238static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3239 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240{
3241 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003242 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3243 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3244 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003245/*
3246 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3247 ace->e_perm, ace->e_tag, ace->e_id);
3248*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
3250 return;
3251}
3252
3253/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003254static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3255 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256{
3257 int size = 0;
3258 int i;
3259 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003260 struct cifs_posix_ace *pACE;
3261 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3262 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263
3264 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3265 return -EOPNOTSUPP;
3266
Steve French790fe572007-07-07 19:25:05 +00003267 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 count = le16_to_cpu(cifs_acl->access_entry_count);
3269 pACE = &cifs_acl->ace_array[0];
3270 size = sizeof(struct cifs_posix_acl);
3271 size += sizeof(struct cifs_posix_ace) * count;
3272 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003273 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003274 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3275 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 return -EINVAL;
3277 }
Steve French790fe572007-07-07 19:25:05 +00003278 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 count = le16_to_cpu(cifs_acl->access_entry_count);
3280 size = sizeof(struct cifs_posix_acl);
3281 size += sizeof(struct cifs_posix_ace) * count;
3282/* skip past access ACEs to get to default ACEs */
3283 pACE = &cifs_acl->ace_array[count];
3284 count = le16_to_cpu(cifs_acl->default_entry_count);
3285 size += sizeof(struct cifs_posix_ace) * count;
3286 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003287 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 return -EINVAL;
3289 } else {
3290 /* illegal type */
3291 return -EINVAL;
3292 }
3293
3294 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003295 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003296 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003297 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 return -ERANGE;
3299 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003300 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003301 for (i = 0; i < count ; i++) {
3302 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3303 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 }
3305 }
3306 return size;
3307}
3308
Steve French50c2f752007-07-13 00:33:32 +00003309static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3310 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311{
3312 __u16 rc = 0; /* 0 = ACL converted ok */
3313
Steve Frenchff7feac2005-11-15 16:45:16 -08003314 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3315 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003317 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 /* Probably no need to le convert -1 on any arch but can not hurt */
3319 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003320 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003321 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003322/*
3323 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3324 ace->e_perm, ace->e_tag, ace->e_id);
3325*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 return rc;
3327}
3328
3329/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003330static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3331 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332{
3333 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003334 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3335 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 int count;
3337 int i;
3338
Steve French790fe572007-07-07 19:25:05 +00003339 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 return 0;
3341
3342 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003343 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3344 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003345 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003346 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3347 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 return 0;
3349 }
3350 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003351 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003352 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003353 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003354 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003356 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 return 0;
3358 }
Steve French50c2f752007-07-13 00:33:32 +00003359 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3361 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003362 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 /* ACE not converted */
3364 break;
3365 }
3366 }
Steve French790fe572007-07-07 19:25:05 +00003367 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3369 rc += sizeof(struct cifs_posix_acl);
3370 /* BB add check to make sure ACL does not overflow SMB */
3371 }
3372 return rc;
3373}
3374
3375int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003376CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003377 const unsigned char *searchName,
3378 char *acl_inf, const int buflen, const int acl_type,
3379 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380{
3381/* SMB_QUERY_POSIX_ACL */
3382 TRANSACTION2_QPI_REQ *pSMB = NULL;
3383 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3384 int rc = 0;
3385 int bytes_returned;
3386 int name_len;
3387 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003388
Joe Perchesf96637b2013-05-04 22:12:25 -05003389 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390
3391queryAclRetry:
3392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3393 (void **) &pSMBr);
3394 if (rc)
3395 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003396
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3398 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003399 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3400 searchName, PATH_MAX, nls_codepage,
3401 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 name_len++; /* trailing null */
3403 name_len *= 2;
3404 pSMB->FileName[name_len] = 0;
3405 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003406 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 name_len = strnlen(searchName, PATH_MAX);
3408 name_len++; /* trailing null */
3409 strncpy(pSMB->FileName, searchName, name_len);
3410 }
3411
3412 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3413 pSMB->TotalDataCount = 0;
3414 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003415 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 pSMB->MaxDataCount = cpu_to_le16(4000);
3417 pSMB->MaxSetupCount = 0;
3418 pSMB->Reserved = 0;
3419 pSMB->Flags = 0;
3420 pSMB->Timeout = 0;
3421 pSMB->Reserved2 = 0;
3422 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003423 offsetof(struct smb_com_transaction2_qpi_req,
3424 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 pSMB->DataCount = 0;
3426 pSMB->DataOffset = 0;
3427 pSMB->SetupCount = 1;
3428 pSMB->Reserved3 = 0;
3429 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3430 byte_count = params + 1 /* pad */ ;
3431 pSMB->TotalParameterCount = cpu_to_le16(params);
3432 pSMB->ParameterCount = pSMB->TotalParameterCount;
3433 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3434 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003435 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 pSMB->ByteCount = cpu_to_le16(byte_count);
3437
3438 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3439 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003440 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003442 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 } else {
3444 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003445
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003448 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 rc = -EIO; /* bad smb */
3450 else {
3451 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3452 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3453 rc = cifs_copy_posix_acl(acl_inf,
3454 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003455 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 }
3457 }
3458 cifs_buf_release(pSMB);
3459 if (rc == -EAGAIN)
3460 goto queryAclRetry;
3461 return rc;
3462}
3463
3464int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003465CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003466 const unsigned char *fileName,
3467 const char *local_acl, const int buflen,
3468 const int acl_type,
3469 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470{
3471 struct smb_com_transaction2_spi_req *pSMB = NULL;
3472 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3473 char *parm_data;
3474 int name_len;
3475 int rc = 0;
3476 int bytes_returned = 0;
3477 __u16 params, byte_count, data_count, param_offset, offset;
3478
Joe Perchesf96637b2013-05-04 22:12:25 -05003479 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480setAclRetry:
3481 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003482 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 if (rc)
3484 return rc;
3485 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3486 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003487 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3488 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 name_len++; /* trailing null */
3490 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003491 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 name_len = strnlen(fileName, PATH_MAX);
3493 name_len++; /* trailing null */
3494 strncpy(pSMB->FileName, fileName, name_len);
3495 }
3496 params = 6 + name_len;
3497 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003498 /* BB find max SMB size from sess */
3499 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 pSMB->MaxSetupCount = 0;
3501 pSMB->Reserved = 0;
3502 pSMB->Flags = 0;
3503 pSMB->Timeout = 0;
3504 pSMB->Reserved2 = 0;
3505 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003506 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 offset = param_offset + params;
3508 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3509 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3510
3511 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003512 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513
Steve French790fe572007-07-07 19:25:05 +00003514 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 rc = -EOPNOTSUPP;
3516 goto setACLerrorExit;
3517 }
3518 pSMB->DataOffset = cpu_to_le16(offset);
3519 pSMB->SetupCount = 1;
3520 pSMB->Reserved3 = 0;
3521 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3522 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3523 byte_count = 3 /* pad */ + params + data_count;
3524 pSMB->DataCount = cpu_to_le16(data_count);
3525 pSMB->TotalDataCount = pSMB->DataCount;
3526 pSMB->ParameterCount = cpu_to_le16(params);
3527 pSMB->TotalParameterCount = pSMB->ParameterCount;
3528 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003529 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 pSMB->ByteCount = cpu_to_le16(byte_count);
3531 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003532 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003533 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003534 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
3536setACLerrorExit:
3537 cifs_buf_release(pSMB);
3538 if (rc == -EAGAIN)
3539 goto setAclRetry;
3540 return rc;
3541}
3542
Steve Frenchf654bac2005-04-28 22:41:04 -07003543/* BB fix tabs in this function FIXME BB */
3544int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003545CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003546 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003547{
Steve French50c2f752007-07-13 00:33:32 +00003548 int rc = 0;
3549 struct smb_t2_qfi_req *pSMB = NULL;
3550 struct smb_t2_qfi_rsp *pSMBr = NULL;
3551 int bytes_returned;
3552 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003553
Joe Perchesf96637b2013-05-04 22:12:25 -05003554 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003555 if (tcon == NULL)
3556 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003557
3558GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003559 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3560 (void **) &pSMBr);
3561 if (rc)
3562 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003563
Steve Frenchad7a2922008-02-07 23:25:02 +00003564 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003565 pSMB->t2.TotalDataCount = 0;
3566 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3567 /* BB find exact max data count below from sess structure BB */
3568 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3569 pSMB->t2.MaxSetupCount = 0;
3570 pSMB->t2.Reserved = 0;
3571 pSMB->t2.Flags = 0;
3572 pSMB->t2.Timeout = 0;
3573 pSMB->t2.Reserved2 = 0;
3574 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3575 Fid) - 4);
3576 pSMB->t2.DataCount = 0;
3577 pSMB->t2.DataOffset = 0;
3578 pSMB->t2.SetupCount = 1;
3579 pSMB->t2.Reserved3 = 0;
3580 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3581 byte_count = params + 1 /* pad */ ;
3582 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3583 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3584 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3585 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003586 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003587 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003588 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003589
Steve French790fe572007-07-07 19:25:05 +00003590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3591 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3592 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003593 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003594 } else {
3595 /* decode response */
3596 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003597 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003598 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003599 /* If rc should we check for EOPNOSUPP and
3600 disable the srvino flag? or in caller? */
3601 rc = -EIO; /* bad smb */
3602 else {
3603 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3604 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3605 struct file_chattr_info *pfinfo;
3606 /* BB Do we need a cast or hash here ? */
3607 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003608 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003609 rc = -EIO;
3610 goto GetExtAttrOut;
3611 }
3612 pfinfo = (struct file_chattr_info *)
3613 (data_offset + (char *) &pSMBr->hdr.Protocol);
3614 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003615 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003616 }
3617 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003618GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003619 cifs_buf_release(pSMB);
3620 if (rc == -EAGAIN)
3621 goto GetExtAttrRetry;
3622 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003623}
3624
Steve Frenchf654bac2005-04-28 22:41:04 -07003625#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626
Jeff Layton79df1ba2010-12-06 12:52:08 -05003627#ifdef CONFIG_CIFS_ACL
3628/*
3629 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3630 * all NT TRANSACTS that we init here have total parm and data under about 400
3631 * bytes (to fit in small cifs buffer size), which is the case so far, it
3632 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3633 * returned setup area) and MaxParameterCount (returned parms size) must be set
3634 * by caller
3635 */
3636static int
3637smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003638 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003639 void **ret_buf)
3640{
3641 int rc;
3642 __u32 temp_offset;
3643 struct smb_com_ntransact_req *pSMB;
3644
3645 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3646 (void **)&pSMB);
3647 if (rc)
3648 return rc;
3649 *ret_buf = (void *)pSMB;
3650 pSMB->Reserved = 0;
3651 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3652 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003653 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003654 pSMB->ParameterCount = pSMB->TotalParameterCount;
3655 pSMB->DataCount = pSMB->TotalDataCount;
3656 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3657 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3658 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3659 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3660 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3661 pSMB->SubCommand = cpu_to_le16(sub_command);
3662 return 0;
3663}
3664
3665static int
3666validate_ntransact(char *buf, char **ppparm, char **ppdata,
3667 __u32 *pparmlen, __u32 *pdatalen)
3668{
3669 char *end_of_smb;
3670 __u32 data_count, data_offset, parm_count, parm_offset;
3671 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003672 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003673
3674 *pdatalen = 0;
3675 *pparmlen = 0;
3676
3677 if (buf == NULL)
3678 return -EINVAL;
3679
3680 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3681
Jeff Layton820a8032011-05-04 08:05:26 -04003682 bcc = get_bcc(&pSMBr->hdr);
3683 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003684 (char *)&pSMBr->ByteCount;
3685
3686 data_offset = le32_to_cpu(pSMBr->DataOffset);
3687 data_count = le32_to_cpu(pSMBr->DataCount);
3688 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3689 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3690
3691 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3692 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3693
3694 /* should we also check that parm and data areas do not overlap? */
3695 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003696 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003697 return -EINVAL;
3698 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003699 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003700 return -EINVAL;
3701 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003702 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003703 return -EINVAL;
3704 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003705 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3706 *ppdata, data_count, (data_count + *ppdata),
3707 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003708 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003709 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003710 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003711 return -EINVAL;
3712 }
3713 *pdatalen = data_count;
3714 *pparmlen = parm_count;
3715 return 0;
3716}
3717
Steve French0a4b92c2006-01-12 15:44:21 -08003718/* Get Security Descriptor (by handle) from remote server for a file or dir */
3719int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003720CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003721 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003722{
3723 int rc = 0;
3724 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003725 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003726 struct kvec iov[1];
3727
Joe Perchesf96637b2013-05-04 22:12:25 -05003728 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003729
Steve French630f3f0c2007-10-25 21:17:17 +00003730 *pbuflen = 0;
3731 *acl_inf = NULL;
3732
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003733 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003734 8 /* parm len */, tcon, (void **) &pSMB);
3735 if (rc)
3736 return rc;
3737
3738 pSMB->MaxParameterCount = cpu_to_le32(4);
3739 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3740 pSMB->MaxSetupCount = 0;
3741 pSMB->Fid = fid; /* file handle always le */
3742 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3743 CIFS_ACL_DACL);
3744 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003745 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003746 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003747 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003748
Steve Frencha761ac52007-10-18 21:45:27 +00003749 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003750 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003751 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003752 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003753 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003754 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003755 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003756 __u32 parm_len;
3757 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003758 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003759 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003760
3761/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003762 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003763 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003764 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003765 goto qsec_out;
3766 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3767
Joe Perchesf96637b2013-05-04 22:12:25 -05003768 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3769 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003770
3771 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3772 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003773 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003774 goto qsec_out;
3775 }
3776
3777/* BB check that data area is minimum length and as big as acl_len */
3778
Steve Frenchaf6f4612007-10-16 18:40:37 +00003779 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003780 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003781 cifs_dbg(VFS, "acl length %d does not match %d\n",
3782 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003783 if (*pbuflen > acl_len)
3784 *pbuflen = acl_len;
3785 }
Steve French0a4b92c2006-01-12 15:44:21 -08003786
Steve French630f3f0c2007-10-25 21:17:17 +00003787 /* check if buffer is big enough for the acl
3788 header followed by the smallest SID */
3789 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3790 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003791 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003792 rc = -EINVAL;
3793 *pbuflen = 0;
3794 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003795 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003796 if (*acl_inf == NULL) {
3797 *pbuflen = 0;
3798 rc = -ENOMEM;
3799 }
Steve French630f3f0c2007-10-25 21:17:17 +00003800 }
Steve French0a4b92c2006-01-12 15:44:21 -08003801 }
3802qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003803 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003804 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003805 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003806 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003807/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003808 return rc;
3809}
Steve French97837582007-12-31 07:47:21 +00003810
3811int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003812CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003813 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003814{
3815 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3816 int rc = 0;
3817 int bytes_returned = 0;
3818 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003819 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003820
3821setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003822 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003823 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003824 return rc;
Steve French97837582007-12-31 07:47:21 +00003825
3826 pSMB->MaxSetupCount = 0;
3827 pSMB->Reserved = 0;
3828
3829 param_count = 8;
3830 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3831 data_count = acllen;
3832 data_offset = param_offset + param_count;
3833 byte_count = 3 /* pad */ + param_count;
3834
3835 pSMB->DataCount = cpu_to_le32(data_count);
3836 pSMB->TotalDataCount = pSMB->DataCount;
3837 pSMB->MaxParameterCount = cpu_to_le32(4);
3838 pSMB->MaxDataCount = cpu_to_le32(16384);
3839 pSMB->ParameterCount = cpu_to_le32(param_count);
3840 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3841 pSMB->TotalParameterCount = pSMB->ParameterCount;
3842 pSMB->DataOffset = cpu_to_le32(data_offset);
3843 pSMB->SetupCount = 0;
3844 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3845 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3846
3847 pSMB->Fid = fid; /* file handle always le */
3848 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003849 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003850
3851 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003852 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3853 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003854 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003855 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003856 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003857
3858 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3860
Joe Perchesf96637b2013-05-04 22:12:25 -05003861 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3862 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003863 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003864 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003865 cifs_buf_release(pSMB);
3866
3867 if (rc == -EAGAIN)
3868 goto setCifsAclRetry;
3869
3870 return (rc);
3871}
3872
Jeff Layton79df1ba2010-12-06 12:52:08 -05003873#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003874
Steve French6b8edfe2005-08-23 20:26:03 -07003875/* Legacy Query Path Information call for lookup to old servers such
3876 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003877int
3878SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3879 const char *search_name, FILE_ALL_INFO *data,
3880 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003881{
Steve Frenchad7a2922008-02-07 23:25:02 +00003882 QUERY_INFORMATION_REQ *pSMB;
3883 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003884 int rc = 0;
3885 int bytes_returned;
3886 int name_len;
3887
Joe Perchesf96637b2013-05-04 22:12:25 -05003888 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003889QInfRetry:
3890 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003891 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003892 if (rc)
3893 return rc;
3894
3895 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3896 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003897 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003898 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003899 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003900 name_len++; /* trailing null */
3901 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003902 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003903 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003904 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003905 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003906 }
3907 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003908 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003909 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003910 pSMB->ByteCount = cpu_to_le16(name_len);
3911
3912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003914 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003915 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003916 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003917 struct timespec ts;
3918 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003919
3920 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003921 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003922 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003923 ts.tv_nsec = 0;
3924 ts.tv_sec = time;
3925 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003926 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3927 data->LastWriteTime = data->ChangeTime;
3928 data->LastAccessTime = 0;
3929 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003930 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003931 data->EndOfFile = data->AllocationSize;
3932 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003933 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003934 } else
3935 rc = -EIO; /* bad buffer passed in */
3936
3937 cifs_buf_release(pSMB);
3938
3939 if (rc == -EAGAIN)
3940 goto QInfRetry;
3941
3942 return rc;
3943}
3944
Jeff Laytonbcd53572010-02-12 07:44:16 -05003945int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003946CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003947 u16 netfid, FILE_ALL_INFO *pFindData)
3948{
3949 struct smb_t2_qfi_req *pSMB = NULL;
3950 struct smb_t2_qfi_rsp *pSMBr = NULL;
3951 int rc = 0;
3952 int bytes_returned;
3953 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003954
Jeff Laytonbcd53572010-02-12 07:44:16 -05003955QFileInfoRetry:
3956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3957 (void **) &pSMBr);
3958 if (rc)
3959 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003960
Jeff Laytonbcd53572010-02-12 07:44:16 -05003961 params = 2 /* level */ + 2 /* fid */;
3962 pSMB->t2.TotalDataCount = 0;
3963 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3964 /* BB find exact max data count below from sess structure BB */
3965 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3966 pSMB->t2.MaxSetupCount = 0;
3967 pSMB->t2.Reserved = 0;
3968 pSMB->t2.Flags = 0;
3969 pSMB->t2.Timeout = 0;
3970 pSMB->t2.Reserved2 = 0;
3971 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3972 Fid) - 4);
3973 pSMB->t2.DataCount = 0;
3974 pSMB->t2.DataOffset = 0;
3975 pSMB->t2.SetupCount = 1;
3976 pSMB->t2.Reserved3 = 0;
3977 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3978 byte_count = params + 1 /* pad */ ;
3979 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3980 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3981 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3982 pSMB->Pad = 0;
3983 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003984 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003985
3986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3988 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003989 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003990 } else { /* decode response */
3991 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3992
3993 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3994 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003995 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003996 rc = -EIO; /* bad smb */
3997 else if (pFindData) {
3998 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3999 memcpy((char *) pFindData,
4000 (char *) &pSMBr->hdr.Protocol +
4001 data_offset, sizeof(FILE_ALL_INFO));
4002 } else
4003 rc = -ENOMEM;
4004 }
4005 cifs_buf_release(pSMB);
4006 if (rc == -EAGAIN)
4007 goto QFileInfoRetry;
4008
4009 return rc;
4010}
Steve French6b8edfe2005-08-23 20:26:03 -07004011
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004013CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004014 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004015 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004016 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004018 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 TRANSACTION2_QPI_REQ *pSMB = NULL;
4020 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4021 int rc = 0;
4022 int bytes_returned;
4023 int name_len;
4024 __u16 params, byte_count;
4025
Joe Perchesf96637b2013-05-04 22:12:25 -05004026 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027QPathInfoRetry:
4028 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4029 (void **) &pSMBr);
4030 if (rc)
4031 return rc;
4032
4033 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4034 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004035 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004036 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 name_len++; /* trailing null */
4038 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004039 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004040 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004042 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 }
4044
Steve French50c2f752007-07-13 00:33:32 +00004045 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 pSMB->TotalDataCount = 0;
4047 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004048 /* BB find exact max SMB PDU from sess structure BB */
4049 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 pSMB->MaxSetupCount = 0;
4051 pSMB->Reserved = 0;
4052 pSMB->Flags = 0;
4053 pSMB->Timeout = 0;
4054 pSMB->Reserved2 = 0;
4055 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004056 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 pSMB->DataCount = 0;
4058 pSMB->DataOffset = 0;
4059 pSMB->SetupCount = 1;
4060 pSMB->Reserved3 = 0;
4061 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4062 byte_count = params + 1 /* pad */ ;
4063 pSMB->TotalParameterCount = cpu_to_le16(params);
4064 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004065 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004066 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4067 else
4068 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004070 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 pSMB->ByteCount = cpu_to_le16(byte_count);
4072
4073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4075 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004076 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 } else { /* decode response */
4078 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4079
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004080 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4081 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004082 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004084 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004085 rc = -EIO; /* 24 or 26 expected but we do not read
4086 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004087 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004088 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004090
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004091 /*
4092 * On legacy responses we do not read the last field,
4093 * EAsize, fortunately since it varies by subdialect and
4094 * also note it differs on Set vs Get, ie two bytes or 4
4095 * bytes depending but we don't care here.
4096 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004097 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004098 size = sizeof(FILE_INFO_STANDARD);
4099 else
4100 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004101 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004102 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 } else
4104 rc = -ENOMEM;
4105 }
4106 cifs_buf_release(pSMB);
4107 if (rc == -EAGAIN)
4108 goto QPathInfoRetry;
4109
4110 return rc;
4111}
4112
4113int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004114CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004115 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4116{
4117 struct smb_t2_qfi_req *pSMB = NULL;
4118 struct smb_t2_qfi_rsp *pSMBr = NULL;
4119 int rc = 0;
4120 int bytes_returned;
4121 __u16 params, byte_count;
4122
4123UnixQFileInfoRetry:
4124 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4125 (void **) &pSMBr);
4126 if (rc)
4127 return rc;
4128
4129 params = 2 /* level */ + 2 /* fid */;
4130 pSMB->t2.TotalDataCount = 0;
4131 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4132 /* BB find exact max data count below from sess structure BB */
4133 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4134 pSMB->t2.MaxSetupCount = 0;
4135 pSMB->t2.Reserved = 0;
4136 pSMB->t2.Flags = 0;
4137 pSMB->t2.Timeout = 0;
4138 pSMB->t2.Reserved2 = 0;
4139 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4140 Fid) - 4);
4141 pSMB->t2.DataCount = 0;
4142 pSMB->t2.DataOffset = 0;
4143 pSMB->t2.SetupCount = 1;
4144 pSMB->t2.Reserved3 = 0;
4145 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4146 byte_count = params + 1 /* pad */ ;
4147 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4148 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4149 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4150 pSMB->Pad = 0;
4151 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004152 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004153
4154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4155 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4156 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004157 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004158 } else { /* decode response */
4159 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4160
Jeff Layton820a8032011-05-04 08:05:26 -04004161 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004162 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 -05004163 rc = -EIO; /* bad smb */
4164 } else {
4165 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4166 memcpy((char *) pFindData,
4167 (char *) &pSMBr->hdr.Protocol +
4168 data_offset,
4169 sizeof(FILE_UNIX_BASIC_INFO));
4170 }
4171 }
4172
4173 cifs_buf_release(pSMB);
4174 if (rc == -EAGAIN)
4175 goto UnixQFileInfoRetry;
4176
4177 return rc;
4178}
4179
4180int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004181CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004183 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004184 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185{
4186/* SMB_QUERY_FILE_UNIX_BASIC */
4187 TRANSACTION2_QPI_REQ *pSMB = NULL;
4188 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4189 int rc = 0;
4190 int bytes_returned = 0;
4191 int name_len;
4192 __u16 params, byte_count;
4193
Joe Perchesf96637b2013-05-04 22:12:25 -05004194 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195UnixQPathInfoRetry:
4196 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4197 (void **) &pSMBr);
4198 if (rc)
4199 return rc;
4200
4201 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4202 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004203 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4204 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 name_len++; /* trailing null */
4206 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004207 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 name_len = strnlen(searchName, PATH_MAX);
4209 name_len++; /* trailing null */
4210 strncpy(pSMB->FileName, searchName, name_len);
4211 }
4212
Steve French50c2f752007-07-13 00:33:32 +00004213 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 pSMB->TotalDataCount = 0;
4215 pSMB->MaxParameterCount = cpu_to_le16(2);
4216 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004217 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 pSMB->MaxSetupCount = 0;
4219 pSMB->Reserved = 0;
4220 pSMB->Flags = 0;
4221 pSMB->Timeout = 0;
4222 pSMB->Reserved2 = 0;
4223 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004224 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 pSMB->DataCount = 0;
4226 pSMB->DataOffset = 0;
4227 pSMB->SetupCount = 1;
4228 pSMB->Reserved3 = 0;
4229 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4230 byte_count = params + 1 /* pad */ ;
4231 pSMB->TotalParameterCount = cpu_to_le16(params);
4232 pSMB->ParameterCount = pSMB->TotalParameterCount;
4233 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4234 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004235 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 pSMB->ByteCount = cpu_to_le16(byte_count);
4237
4238 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4239 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4240 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004241 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 } else { /* decode response */
4243 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4244
Jeff Layton820a8032011-05-04 08:05:26 -04004245 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004246 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 -07004247 rc = -EIO; /* bad smb */
4248 } else {
4249 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4250 memcpy((char *) pFindData,
4251 (char *) &pSMBr->hdr.Protocol +
4252 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004253 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 }
4255 }
4256 cifs_buf_release(pSMB);
4257 if (rc == -EAGAIN)
4258 goto UnixQPathInfoRetry;
4259
4260 return rc;
4261}
4262
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263/* xid, tcon, searchName and codepage are input parms, rest are returned */
4264int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004265CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004266 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004267 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004268 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269{
4270/* level 257 SMB_ */
4271 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4272 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004273 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 int rc = 0;
4275 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004276 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004278 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279
Joe Perchesf96637b2013-05-04 22:12:25 -05004280 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281
4282findFirstRetry:
4283 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4284 (void **) &pSMBr);
4285 if (rc)
4286 return rc;
4287
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004288 nls_codepage = cifs_sb->local_nls;
4289 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4290
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4292 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004293 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4294 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004295 /* We can not add the asterik earlier in case
4296 it got remapped to 0xF03A as if it were part of the
4297 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004299 if (msearch) {
4300 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4301 pSMB->FileName[name_len+1] = 0;
4302 pSMB->FileName[name_len+2] = '*';
4303 pSMB->FileName[name_len+3] = 0;
4304 name_len += 4; /* now the trailing null */
4305 /* null terminate just in case */
4306 pSMB->FileName[name_len] = 0;
4307 pSMB->FileName[name_len+1] = 0;
4308 name_len += 2;
4309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 } else { /* BB add check for overrun of SMB buf BB */
4311 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004313 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 free buffer exit; BB */
4315 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004316 if (msearch) {
4317 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4318 pSMB->FileName[name_len+1] = '*';
4319 pSMB->FileName[name_len+2] = 0;
4320 name_len += 3;
4321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 }
4323
4324 params = 12 + name_len /* includes null */ ;
4325 pSMB->TotalDataCount = 0; /* no EAs */
4326 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004327 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 pSMB->MaxSetupCount = 0;
4329 pSMB->Reserved = 0;
4330 pSMB->Flags = 0;
4331 pSMB->Timeout = 0;
4332 pSMB->Reserved2 = 0;
4333 byte_count = params + 1 /* pad */ ;
4334 pSMB->TotalParameterCount = cpu_to_le16(params);
4335 pSMB->ParameterCount = pSMB->TotalParameterCount;
4336 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004337 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4338 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 pSMB->DataCount = 0;
4340 pSMB->DataOffset = 0;
4341 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4342 pSMB->Reserved3 = 0;
4343 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4344 pSMB->SearchAttributes =
4345 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4346 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004347 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004348 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4350
4351 /* BB what should we set StorageType to? Does it matter? BB */
4352 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004353 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 pSMB->ByteCount = cpu_to_le16(byte_count);
4355
4356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004358 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359
Steve French88274812006-03-09 22:21:45 +00004360 if (rc) {/* BB add logic to retry regular search if Unix search
4361 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004363 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004364
Steve French88274812006-03-09 22:21:45 +00004365 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366
4367 /* BB eventually could optimize out free and realloc of buf */
4368 /* for this case */
4369 if (rc == -EAGAIN)
4370 goto findFirstRetry;
4371 } else { /* decode response */
4372 /* BB remember to free buffer if error BB */
4373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004374 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004375 unsigned int lnoff;
4376
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004378 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 else
Steve French4b18f2a2008-04-29 00:06:05 +00004380 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
4382 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004383 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004384 psrch_inf->srch_entries_start =
4385 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4388 le16_to_cpu(pSMBr->t2.ParameterOffset));
4389
Steve French790fe572007-07-07 19:25:05 +00004390 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004391 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 else
Steve French4b18f2a2008-04-29 00:06:05 +00004393 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
Steve French50c2f752007-07-13 00:33:32 +00004395 psrch_inf->entries_in_buffer =
4396 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004397 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004399 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004400 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004401 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004402 psrch_inf->last_entry = NULL;
4403 return rc;
4404 }
4405
Steve French0752f152008-10-07 20:03:33 +00004406 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004407 lnoff;
4408
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004409 if (pnetfid)
4410 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 } else {
4412 cifs_buf_release(pSMB);
4413 }
4414 }
4415
4416 return rc;
4417}
4418
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004419int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4420 __u16 searchHandle, __u16 search_flags,
4421 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422{
4423 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4424 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004425 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 char *response_data;
4427 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004428 int bytes_returned;
4429 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 __u16 params, byte_count;
4431
Joe Perchesf96637b2013-05-04 22:12:25 -05004432 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
Steve French4b18f2a2008-04-29 00:06:05 +00004434 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 return -ENOENT;
4436
4437 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4438 (void **) &pSMBr);
4439 if (rc)
4440 return rc;
4441
Steve French50c2f752007-07-13 00:33:32 +00004442 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 byte_count = 0;
4444 pSMB->TotalDataCount = 0; /* no EAs */
4445 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004446 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 pSMB->MaxSetupCount = 0;
4448 pSMB->Reserved = 0;
4449 pSMB->Flags = 0;
4450 pSMB->Timeout = 0;
4451 pSMB->Reserved2 = 0;
4452 pSMB->ParameterOffset = cpu_to_le16(
4453 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4454 pSMB->DataCount = 0;
4455 pSMB->DataOffset = 0;
4456 pSMB->SetupCount = 1;
4457 pSMB->Reserved3 = 0;
4458 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4459 pSMB->SearchHandle = searchHandle; /* always kept as le */
4460 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004461 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4463 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004464 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
4466 name_len = psrch_inf->resume_name_len;
4467 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004468 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4470 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004471 /* 14 byte parm len above enough for 2 byte null terminator */
4472 pSMB->ResumeFileName[name_len] = 0;
4473 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 } else {
4475 rc = -EINVAL;
4476 goto FNext2_err_exit;
4477 }
4478 byte_count = params + 1 /* pad */ ;
4479 pSMB->TotalParameterCount = cpu_to_le16(params);
4480 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004481 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004483
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004486 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 if (rc) {
4488 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004489 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004490 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004491 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004493 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 } else { /* decode response */
4495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004496
Steve French790fe572007-07-07 19:25:05 +00004497 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004498 unsigned int lnoff;
4499
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 /* BB fixme add lock for file (srch_info) struct here */
4501 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004502 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 else
Steve French4b18f2a2008-04-29 00:06:05 +00004504 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 response_data = (char *) &pSMBr->hdr.Protocol +
4506 le16_to_cpu(pSMBr->t2.ParameterOffset);
4507 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4508 response_data = (char *)&pSMBr->hdr.Protocol +
4509 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004510 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004511 cifs_small_buf_release(
4512 psrch_inf->ntwrk_buf_start);
4513 else
4514 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 psrch_inf->srch_entries_start = response_data;
4516 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004517 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004518 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004519 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 else
Steve French4b18f2a2008-04-29 00:06:05 +00004521 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004522 psrch_inf->entries_in_buffer =
4523 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 psrch_inf->index_of_last_entry +=
4525 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004526 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004527 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004528 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004529 psrch_inf->last_entry = NULL;
4530 return rc;
4531 } else
4532 psrch_inf->last_entry =
4533 psrch_inf->srch_entries_start + lnoff;
4534
Joe Perchesf96637b2013-05-04 22:12:25 -05004535/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4536 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
4538 /* BB fixme add unlock here */
4539 }
4540
4541 }
4542
4543 /* BB On error, should we leave previous search buf (and count and
4544 last entry fields) intact or free the previous one? */
4545
4546 /* Note: On -EAGAIN error only caller can retry on handle based calls
4547 since file handle passed in no longer valid */
4548FNext2_err_exit:
4549 if (rc != 0)
4550 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 return rc;
4552}
4553
4554int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004555CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004556 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557{
4558 int rc = 0;
4559 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560
Joe Perchesf96637b2013-05-04 22:12:25 -05004561 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4563
4564 /* no sense returning error if session restarted
4565 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004566 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 return 0;
4568 if (rc)
4569 return rc;
4570
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 pSMB->FileID = searchHandle;
4572 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004573 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004574 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004575 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004576
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004577 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578
4579 /* Since session is dead, search handle closed on server already */
4580 if (rc == -EAGAIN)
4581 rc = 0;
4582
4583 return rc;
4584}
4585
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004587CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004588 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004589 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590{
4591 int rc = 0;
4592 TRANSACTION2_QPI_REQ *pSMB = NULL;
4593 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4594 int name_len, bytes_returned;
4595 __u16 params, byte_count;
4596
Joe Perchesf96637b2013-05-04 22:12:25 -05004597 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004598 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004599 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600
4601GetInodeNumberRetry:
4602 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004603 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 if (rc)
4605 return rc;
4606
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4608 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004609 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004610 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004611 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 name_len++; /* trailing null */
4613 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004614 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004615 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004617 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 }
4619
4620 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4621 pSMB->TotalDataCount = 0;
4622 pSMB->MaxParameterCount = cpu_to_le16(2);
4623 /* BB find exact max data count below from sess structure BB */
4624 pSMB->MaxDataCount = cpu_to_le16(4000);
4625 pSMB->MaxSetupCount = 0;
4626 pSMB->Reserved = 0;
4627 pSMB->Flags = 0;
4628 pSMB->Timeout = 0;
4629 pSMB->Reserved2 = 0;
4630 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004631 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 pSMB->DataCount = 0;
4633 pSMB->DataOffset = 0;
4634 pSMB->SetupCount = 1;
4635 pSMB->Reserved3 = 0;
4636 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4637 byte_count = params + 1 /* pad */ ;
4638 pSMB->TotalParameterCount = cpu_to_le16(params);
4639 pSMB->ParameterCount = pSMB->TotalParameterCount;
4640 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4641 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004642 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 pSMB->ByteCount = cpu_to_le16(byte_count);
4644
4645 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4646 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4647 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004648 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 } else {
4650 /* decode response */
4651 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004653 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 /* If rc should we check for EOPNOSUPP and
4655 disable the srvino flag? or in caller? */
4656 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004657 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4659 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004660 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004662 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004663 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 rc = -EIO;
4665 goto GetInodeNumOut;
4666 }
4667 pfinfo = (struct file_internal_info *)
4668 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004669 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 }
4671 }
4672GetInodeNumOut:
4673 cifs_buf_release(pSMB);
4674 if (rc == -EAGAIN)
4675 goto GetInodeNumberRetry;
4676 return rc;
4677}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
Igor Mammedovfec45852008-05-16 13:06:30 +04004679/* parses DFS refferal V3 structure
4680 * caller is responsible for freeing target_nodes
4681 * returns:
4682 * on success - 0
4683 * on failure - errno
4684 */
4685static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004686parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004687 unsigned int *num_of_nodes,
4688 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004689 const struct nls_table *nls_codepage, int remap,
4690 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004691{
4692 int i, rc = 0;
4693 char *data_end;
4694 bool is_unicode;
4695 struct dfs_referral_level_3 *ref;
4696
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004697 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4698 is_unicode = true;
4699 else
4700 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004701 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4702
4703 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004704 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4705 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004706 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004707 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004708 }
4709
4710 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004711 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004712 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4713 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004714 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004715 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004716 }
4717
4718 /* get the upper boundary of the resp buffer */
4719 data_end = (char *)(&(pSMBr->PathConsumed)) +
4720 le16_to_cpu(pSMBr->t2.DataCount);
4721
Joe Perchesf96637b2013-05-04 22:12:25 -05004722 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4723 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004724
Joe Perchesf96637b2013-05-04 22:12:25 -05004725 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4726 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004727 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004728 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004729 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004730 }
4731
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004732 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004733 for (i = 0; i < *num_of_nodes; i++) {
4734 char *temp;
4735 int max_len;
4736 struct dfs_info3_param *node = (*target_nodes)+i;
4737
Steve French0e0d2cf2009-05-01 05:27:32 +00004738 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004739 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004740 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4741 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004742 if (tmp == NULL) {
4743 rc = -ENOMEM;
4744 goto parse_DFS_referrals_exit;
4745 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004746 cifsConvertToUTF16((__le16 *) tmp, searchName,
4747 PATH_MAX, nls_codepage, remap);
4748 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004749 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004750 nls_codepage);
4751 kfree(tmp);
4752 } else
4753 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4754
Igor Mammedovfec45852008-05-16 13:06:30 +04004755 node->server_type = le16_to_cpu(ref->ServerType);
4756 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4757
4758 /* copy DfsPath */
4759 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4760 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004761 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4762 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004763 if (!node->path_name) {
4764 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004765 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004766 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004767
4768 /* copy link target UNC */
4769 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4770 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004771 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4772 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004773 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004774 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004775 goto parse_DFS_referrals_exit;
4776 }
4777
4778 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004779 }
4780
Steve Frencha1fe78f2008-05-16 18:48:38 +00004781parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004782 if (rc) {
4783 free_dfs_info_array(*target_nodes, *num_of_nodes);
4784 *target_nodes = NULL;
4785 *num_of_nodes = 0;
4786 }
4787 return rc;
4788}
4789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004791CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004792 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004793 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004794 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795{
4796/* TRANS2_GET_DFS_REFERRAL */
4797 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4798 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 int rc = 0;
4800 int bytes_returned;
4801 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004803 *num_of_nodes = 0;
4804 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805
Joe Perchesf96637b2013-05-04 22:12:25 -05004806 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 if (ses == NULL)
4808 return -ENODEV;
4809getDFSRetry:
4810 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4811 (void **) &pSMBr);
4812 if (rc)
4813 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004814
4815 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004816 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004817 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 pSMB->hdr.Tid = ses->ipc_tid;
4819 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004820 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004822 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824
4825 if (ses->capabilities & CAP_UNICODE) {
4826 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4827 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004828 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004829 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004830 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 name_len++; /* trailing null */
4832 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004833 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004834 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004836 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 }
4838
Jeff Layton38d77c52013-05-26 07:01:00 -04004839 if (ses->server && ses->server->sign)
4840 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004841
Steve French50c2f752007-07-13 00:33:32 +00004842 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004843
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 params = 2 /* level */ + name_len /*includes null */ ;
4845 pSMB->TotalDataCount = 0;
4846 pSMB->DataCount = 0;
4847 pSMB->DataOffset = 0;
4848 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004849 /* BB find exact max SMB PDU from sess structure BB */
4850 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 pSMB->MaxSetupCount = 0;
4852 pSMB->Reserved = 0;
4853 pSMB->Flags = 0;
4854 pSMB->Timeout = 0;
4855 pSMB->Reserved2 = 0;
4856 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004857 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 pSMB->SetupCount = 1;
4859 pSMB->Reserved3 = 0;
4860 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4861 byte_count = params + 3 /* pad */ ;
4862 pSMB->ParameterCount = cpu_to_le16(params);
4863 pSMB->TotalParameterCount = pSMB->ParameterCount;
4864 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004865 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 pSMB->ByteCount = cpu_to_le16(byte_count);
4867
4868 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4870 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004871 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004872 goto GetDFSRefExit;
4873 }
4874 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004876 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004877 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004878 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004879 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004881
Joe Perchesf96637b2013-05-04 22:12:25 -05004882 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4883 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004884
4885 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004886 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004887 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004888 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004889
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004891 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
4893 if (rc == -EAGAIN)
4894 goto getDFSRetry;
4895
4896 return rc;
4897}
4898
Steve French20962432005-09-21 22:05:57 -07004899/* Query File System Info such as free space to old servers such as Win 9x */
4900int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004901SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4902 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004903{
4904/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4905 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4906 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4907 FILE_SYSTEM_ALLOC_INFO *response_data;
4908 int rc = 0;
4909 int bytes_returned = 0;
4910 __u16 params, byte_count;
4911
Joe Perchesf96637b2013-05-04 22:12:25 -05004912 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004913oldQFSInfoRetry:
4914 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4915 (void **) &pSMBr);
4916 if (rc)
4917 return rc;
Steve French20962432005-09-21 22:05:57 -07004918
4919 params = 2; /* level */
4920 pSMB->TotalDataCount = 0;
4921 pSMB->MaxParameterCount = cpu_to_le16(2);
4922 pSMB->MaxDataCount = cpu_to_le16(1000);
4923 pSMB->MaxSetupCount = 0;
4924 pSMB->Reserved = 0;
4925 pSMB->Flags = 0;
4926 pSMB->Timeout = 0;
4927 pSMB->Reserved2 = 0;
4928 byte_count = params + 1 /* pad */ ;
4929 pSMB->TotalParameterCount = cpu_to_le16(params);
4930 pSMB->ParameterCount = pSMB->TotalParameterCount;
4931 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4932 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4933 pSMB->DataCount = 0;
4934 pSMB->DataOffset = 0;
4935 pSMB->SetupCount = 1;
4936 pSMB->Reserved3 = 0;
4937 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4938 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004939 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004940 pSMB->ByteCount = cpu_to_le16(byte_count);
4941
4942 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4943 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4944 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004945 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004946 } else { /* decode response */
4947 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4948
Jeff Layton820a8032011-05-04 08:05:26 -04004949 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004950 rc = -EIO; /* bad smb */
4951 else {
4952 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004953 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004954 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004955
Steve French50c2f752007-07-13 00:33:32 +00004956 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004957 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4958 FSData->f_bsize =
4959 le16_to_cpu(response_data->BytesPerSector) *
4960 le32_to_cpu(response_data->
4961 SectorsPerAllocationUnit);
4962 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004963 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004964 FSData->f_bfree = FSData->f_bavail =
4965 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004966 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4967 (unsigned long long)FSData->f_blocks,
4968 (unsigned long long)FSData->f_bfree,
4969 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004970 }
4971 }
4972 cifs_buf_release(pSMB);
4973
4974 if (rc == -EAGAIN)
4975 goto oldQFSInfoRetry;
4976
4977 return rc;
4978}
4979
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004981CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4982 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983{
4984/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4985 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4986 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4987 FILE_SYSTEM_INFO *response_data;
4988 int rc = 0;
4989 int bytes_returned = 0;
4990 __u16 params, byte_count;
4991
Joe Perchesf96637b2013-05-04 22:12:25 -05004992 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993QFSInfoRetry:
4994 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4995 (void **) &pSMBr);
4996 if (rc)
4997 return rc;
4998
4999 params = 2; /* level */
5000 pSMB->TotalDataCount = 0;
5001 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005002 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 pSMB->MaxSetupCount = 0;
5004 pSMB->Reserved = 0;
5005 pSMB->Flags = 0;
5006 pSMB->Timeout = 0;
5007 pSMB->Reserved2 = 0;
5008 byte_count = params + 1 /* pad */ ;
5009 pSMB->TotalParameterCount = cpu_to_le16(params);
5010 pSMB->ParameterCount = pSMB->TotalParameterCount;
5011 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005012 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 pSMB->DataCount = 0;
5014 pSMB->DataOffset = 0;
5015 pSMB->SetupCount = 1;
5016 pSMB->Reserved3 = 0;
5017 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5018 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005019 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 pSMB->ByteCount = cpu_to_le16(byte_count);
5021
5022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5024 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005025 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005027 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028
Jeff Layton820a8032011-05-04 08:05:26 -04005029 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 rc = -EIO; /* bad smb */
5031 else {
5032 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033
5034 response_data =
5035 (FILE_SYSTEM_INFO
5036 *) (((char *) &pSMBr->hdr.Protocol) +
5037 data_offset);
5038 FSData->f_bsize =
5039 le32_to_cpu(response_data->BytesPerSector) *
5040 le32_to_cpu(response_data->
5041 SectorsPerAllocationUnit);
5042 FSData->f_blocks =
5043 le64_to_cpu(response_data->TotalAllocationUnits);
5044 FSData->f_bfree = FSData->f_bavail =
5045 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005046 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5047 (unsigned long long)FSData->f_blocks,
5048 (unsigned long long)FSData->f_bfree,
5049 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 }
5051 }
5052 cifs_buf_release(pSMB);
5053
5054 if (rc == -EAGAIN)
5055 goto QFSInfoRetry;
5056
5057 return rc;
5058}
5059
5060int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005061CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062{
5063/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5064 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5065 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5066 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5067 int rc = 0;
5068 int bytes_returned = 0;
5069 __u16 params, byte_count;
5070
Joe Perchesf96637b2013-05-04 22:12:25 -05005071 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072QFSAttributeRetry:
5073 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5074 (void **) &pSMBr);
5075 if (rc)
5076 return rc;
5077
5078 params = 2; /* level */
5079 pSMB->TotalDataCount = 0;
5080 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005081 /* BB find exact max SMB PDU from sess structure BB */
5082 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 pSMB->MaxSetupCount = 0;
5084 pSMB->Reserved = 0;
5085 pSMB->Flags = 0;
5086 pSMB->Timeout = 0;
5087 pSMB->Reserved2 = 0;
5088 byte_count = params + 1 /* pad */ ;
5089 pSMB->TotalParameterCount = cpu_to_le16(params);
5090 pSMB->ParameterCount = pSMB->TotalParameterCount;
5091 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005092 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 pSMB->DataCount = 0;
5094 pSMB->DataOffset = 0;
5095 pSMB->SetupCount = 1;
5096 pSMB->Reserved3 = 0;
5097 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5098 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005099 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 pSMB->ByteCount = cpu_to_le16(byte_count);
5101
5102 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5104 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005105 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 } else { /* decode response */
5107 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5108
Jeff Layton820a8032011-05-04 08:05:26 -04005109 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005110 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 rc = -EIO; /* bad smb */
5112 } else {
5113 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5114 response_data =
5115 (FILE_SYSTEM_ATTRIBUTE_INFO
5116 *) (((char *) &pSMBr->hdr.Protocol) +
5117 data_offset);
5118 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005119 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 }
5121 }
5122 cifs_buf_release(pSMB);
5123
5124 if (rc == -EAGAIN)
5125 goto QFSAttributeRetry;
5126
5127 return rc;
5128}
5129
5130int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005131CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132{
5133/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5134 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5135 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5136 FILE_SYSTEM_DEVICE_INFO *response_data;
5137 int rc = 0;
5138 int bytes_returned = 0;
5139 __u16 params, byte_count;
5140
Joe Perchesf96637b2013-05-04 22:12:25 -05005141 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142QFSDeviceRetry:
5143 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5144 (void **) &pSMBr);
5145 if (rc)
5146 return rc;
5147
5148 params = 2; /* level */
5149 pSMB->TotalDataCount = 0;
5150 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005151 /* BB find exact max SMB PDU from sess structure BB */
5152 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 pSMB->MaxSetupCount = 0;
5154 pSMB->Reserved = 0;
5155 pSMB->Flags = 0;
5156 pSMB->Timeout = 0;
5157 pSMB->Reserved2 = 0;
5158 byte_count = params + 1 /* pad */ ;
5159 pSMB->TotalParameterCount = cpu_to_le16(params);
5160 pSMB->ParameterCount = pSMB->TotalParameterCount;
5161 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005162 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163
5164 pSMB->DataCount = 0;
5165 pSMB->DataOffset = 0;
5166 pSMB->SetupCount = 1;
5167 pSMB->Reserved3 = 0;
5168 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5169 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005170 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 pSMB->ByteCount = cpu_to_le16(byte_count);
5172
5173 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5174 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5175 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005176 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 } else { /* decode response */
5178 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5179
Jeff Layton820a8032011-05-04 08:05:26 -04005180 if (rc || get_bcc(&pSMBr->hdr) <
5181 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 rc = -EIO; /* bad smb */
5183 else {
5184 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5185 response_data =
Steve French737b7582005-04-28 22:41:06 -07005186 (FILE_SYSTEM_DEVICE_INFO *)
5187 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 data_offset);
5189 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005190 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 }
5192 }
5193 cifs_buf_release(pSMB);
5194
5195 if (rc == -EAGAIN)
5196 goto QFSDeviceRetry;
5197
5198 return rc;
5199}
5200
5201int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005202CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203{
5204/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5205 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5206 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5207 FILE_SYSTEM_UNIX_INFO *response_data;
5208 int rc = 0;
5209 int bytes_returned = 0;
5210 __u16 params, byte_count;
5211
Joe Perchesf96637b2013-05-04 22:12:25 -05005212 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005214 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5215 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 if (rc)
5217 return rc;
5218
5219 params = 2; /* level */
5220 pSMB->TotalDataCount = 0;
5221 pSMB->DataCount = 0;
5222 pSMB->DataOffset = 0;
5223 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005224 /* BB find exact max SMB PDU from sess structure BB */
5225 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 pSMB->MaxSetupCount = 0;
5227 pSMB->Reserved = 0;
5228 pSMB->Flags = 0;
5229 pSMB->Timeout = 0;
5230 pSMB->Reserved2 = 0;
5231 byte_count = params + 1 /* pad */ ;
5232 pSMB->ParameterCount = cpu_to_le16(params);
5233 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005234 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5235 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 pSMB->SetupCount = 1;
5237 pSMB->Reserved3 = 0;
5238 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5239 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005240 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 pSMB->ByteCount = cpu_to_le16(byte_count);
5242
5243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5245 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005246 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 } else { /* decode response */
5248 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5249
Jeff Layton820a8032011-05-04 08:05:26 -04005250 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 rc = -EIO; /* bad smb */
5252 } else {
5253 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5254 response_data =
5255 (FILE_SYSTEM_UNIX_INFO
5256 *) (((char *) &pSMBr->hdr.Protocol) +
5257 data_offset);
5258 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005259 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 }
5261 }
5262 cifs_buf_release(pSMB);
5263
5264 if (rc == -EAGAIN)
5265 goto QFSUnixRetry;
5266
5267
5268 return rc;
5269}
5270
Jeremy Allisonac670552005-06-22 17:26:35 -07005271int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005272CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005273{
5274/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5275 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5276 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5277 int rc = 0;
5278 int bytes_returned = 0;
5279 __u16 params, param_offset, offset, byte_count;
5280
Joe Perchesf96637b2013-05-04 22:12:25 -05005281 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005282SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005283 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005284 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5285 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005286 if (rc)
5287 return rc;
5288
5289 params = 4; /* 2 bytes zero followed by info level. */
5290 pSMB->MaxSetupCount = 0;
5291 pSMB->Reserved = 0;
5292 pSMB->Flags = 0;
5293 pSMB->Timeout = 0;
5294 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005295 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5296 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005297 offset = param_offset + params;
5298
5299 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005300 /* BB find exact max SMB PDU from sess structure BB */
5301 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005302 pSMB->SetupCount = 1;
5303 pSMB->Reserved3 = 0;
5304 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5305 byte_count = 1 /* pad */ + params + 12;
5306
5307 pSMB->DataCount = cpu_to_le16(12);
5308 pSMB->ParameterCount = cpu_to_le16(params);
5309 pSMB->TotalDataCount = pSMB->DataCount;
5310 pSMB->TotalParameterCount = pSMB->ParameterCount;
5311 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5312 pSMB->DataOffset = cpu_to_le16(offset);
5313
5314 /* Params. */
5315 pSMB->FileNum = 0;
5316 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5317
5318 /* Data. */
5319 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5320 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5321 pSMB->ClientUnixCap = cpu_to_le64(cap);
5322
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005323 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005324 pSMB->ByteCount = cpu_to_le16(byte_count);
5325
5326 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5327 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5328 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005329 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005330 } else { /* decode response */
5331 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005332 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005333 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005334 }
5335 cifs_buf_release(pSMB);
5336
5337 if (rc == -EAGAIN)
5338 goto SETFSUnixRetry;
5339
5340 return rc;
5341}
5342
5343
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
5345int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005346CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005347 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348{
5349/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5350 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5351 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5352 FILE_SYSTEM_POSIX_INFO *response_data;
5353 int rc = 0;
5354 int bytes_returned = 0;
5355 __u16 params, byte_count;
5356
Joe Perchesf96637b2013-05-04 22:12:25 -05005357 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358QFSPosixRetry:
5359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5360 (void **) &pSMBr);
5361 if (rc)
5362 return rc;
5363
5364 params = 2; /* level */
5365 pSMB->TotalDataCount = 0;
5366 pSMB->DataCount = 0;
5367 pSMB->DataOffset = 0;
5368 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005369 /* BB find exact max SMB PDU from sess structure BB */
5370 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 pSMB->MaxSetupCount = 0;
5372 pSMB->Reserved = 0;
5373 pSMB->Flags = 0;
5374 pSMB->Timeout = 0;
5375 pSMB->Reserved2 = 0;
5376 byte_count = params + 1 /* pad */ ;
5377 pSMB->ParameterCount = cpu_to_le16(params);
5378 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005379 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5380 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 pSMB->SetupCount = 1;
5382 pSMB->Reserved3 = 0;
5383 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5384 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005385 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 pSMB->ByteCount = cpu_to_le16(byte_count);
5387
5388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5390 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005391 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 } else { /* decode response */
5393 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5394
Jeff Layton820a8032011-05-04 08:05:26 -04005395 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 rc = -EIO; /* bad smb */
5397 } else {
5398 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5399 response_data =
5400 (FILE_SYSTEM_POSIX_INFO
5401 *) (((char *) &pSMBr->hdr.Protocol) +
5402 data_offset);
5403 FSData->f_bsize =
5404 le32_to_cpu(response_data->BlockSize);
5405 FSData->f_blocks =
5406 le64_to_cpu(response_data->TotalBlocks);
5407 FSData->f_bfree =
5408 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005409 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 FSData->f_bavail = FSData->f_bfree;
5411 } else {
5412 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005413 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 }
Steve French790fe572007-07-07 19:25:05 +00005415 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005417 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005418 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005420 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 }
5422 }
5423 cifs_buf_release(pSMB);
5424
5425 if (rc == -EAGAIN)
5426 goto QFSPosixRetry;
5427
5428 return rc;
5429}
5430
5431
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005432/*
5433 * We can not use write of zero bytes trick to set file size due to need for
5434 * large file support. Also note that this SetPathInfo is preferred to
5435 * SetFileInfo based method in next routine which is only needed to work around
5436 * a sharing violation bugin Samba which this routine can run into.
5437 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005439CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005440 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5441 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442{
5443 struct smb_com_transaction2_spi_req *pSMB = NULL;
5444 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5445 struct file_end_of_file_info *parm_data;
5446 int name_len;
5447 int rc = 0;
5448 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005449 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5450
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 __u16 params, byte_count, data_count, param_offset, offset;
5452
Joe Perchesf96637b2013-05-04 22:12:25 -05005453 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454SetEOFRetry:
5455 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5456 (void **) &pSMBr);
5457 if (rc)
5458 return rc;
5459
5460 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5461 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005462 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5463 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 name_len++; /* trailing null */
5465 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005466 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005467 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005469 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 }
5471 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005472 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005474 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 pSMB->MaxSetupCount = 0;
5476 pSMB->Reserved = 0;
5477 pSMB->Flags = 0;
5478 pSMB->Timeout = 0;
5479 pSMB->Reserved2 = 0;
5480 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005481 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005483 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005484 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5485 pSMB->InformationLevel =
5486 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5487 else
5488 pSMB->InformationLevel =
5489 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5490 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5492 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005493 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 else
5495 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005496 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 }
5498
5499 parm_data =
5500 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5501 offset);
5502 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5503 pSMB->DataOffset = cpu_to_le16(offset);
5504 pSMB->SetupCount = 1;
5505 pSMB->Reserved3 = 0;
5506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5507 byte_count = 3 /* pad */ + params + data_count;
5508 pSMB->DataCount = cpu_to_le16(data_count);
5509 pSMB->TotalDataCount = pSMB->DataCount;
5510 pSMB->ParameterCount = cpu_to_le16(params);
5511 pSMB->TotalParameterCount = pSMB->ParameterCount;
5512 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005513 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 parm_data->FileSize = cpu_to_le64(size);
5515 pSMB->ByteCount = cpu_to_le16(byte_count);
5516 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5517 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005518 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005519 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520
5521 cifs_buf_release(pSMB);
5522
5523 if (rc == -EAGAIN)
5524 goto SetEOFRetry;
5525
5526 return rc;
5527}
5528
5529int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005530CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5531 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532{
5533 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 struct file_end_of_file_info *parm_data;
5535 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 __u16 params, param_offset, offset, byte_count, count;
5537
Joe Perchesf96637b2013-05-04 22:12:25 -05005538 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5539 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005540 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5541
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 if (rc)
5543 return rc;
5544
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005545 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5546 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005547
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 params = 6;
5549 pSMB->MaxSetupCount = 0;
5550 pSMB->Reserved = 0;
5551 pSMB->Flags = 0;
5552 pSMB->Timeout = 0;
5553 pSMB->Reserved2 = 0;
5554 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5555 offset = param_offset + params;
5556
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 count = sizeof(struct file_end_of_file_info);
5558 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005559 /* BB find exact max SMB PDU from sess structure BB */
5560 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 pSMB->SetupCount = 1;
5562 pSMB->Reserved3 = 0;
5563 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5564 byte_count = 3 /* pad */ + params + count;
5565 pSMB->DataCount = cpu_to_le16(count);
5566 pSMB->ParameterCount = cpu_to_le16(params);
5567 pSMB->TotalDataCount = pSMB->DataCount;
5568 pSMB->TotalParameterCount = pSMB->ParameterCount;
5569 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5570 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005571 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5572 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 pSMB->DataOffset = cpu_to_le16(offset);
5574 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005575 pSMB->Fid = cfile->fid.netfid;
5576 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5578 pSMB->InformationLevel =
5579 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5580 else
5581 pSMB->InformationLevel =
5582 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005583 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5585 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005586 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 else
5588 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005589 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 }
5591 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005592 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005594 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005596 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5597 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 }
5599
Steve French50c2f752007-07-13 00:33:32 +00005600 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 since file handle passed in no longer valid */
5602
5603 return rc;
5604}
5605
Steve French50c2f752007-07-13 00:33:32 +00005606/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 an open handle, rather than by pathname - this is awkward due to
5608 potential access conflicts on the open, but it is unavoidable for these
5609 old servers since the only other choice is to go from 100 nanosecond DCE
5610 time and resort to the original setpathinfo level which takes the ancient
5611 DOS time format with 2 second granularity */
5612int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005613CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005614 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615{
5616 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 char *data_offset;
5618 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 __u16 params, param_offset, offset, byte_count, count;
5620
Joe Perchesf96637b2013-05-04 22:12:25 -05005621 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005622 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5623
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 if (rc)
5625 return rc;
5626
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005627 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5628 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005629
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 params = 6;
5631 pSMB->MaxSetupCount = 0;
5632 pSMB->Reserved = 0;
5633 pSMB->Flags = 0;
5634 pSMB->Timeout = 0;
5635 pSMB->Reserved2 = 0;
5636 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5637 offset = param_offset + params;
5638
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005639 data_offset = (char *)pSMB +
5640 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641
Steve French26f57362007-08-30 22:09:15 +00005642 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005644 /* BB find max SMB PDU from sess */
5645 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 pSMB->SetupCount = 1;
5647 pSMB->Reserved3 = 0;
5648 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5649 byte_count = 3 /* pad */ + params + count;
5650 pSMB->DataCount = cpu_to_le16(count);
5651 pSMB->ParameterCount = cpu_to_le16(params);
5652 pSMB->TotalDataCount = pSMB->DataCount;
5653 pSMB->TotalParameterCount = pSMB->ParameterCount;
5654 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5655 pSMB->DataOffset = cpu_to_le16(offset);
5656 pSMB->Fid = fid;
5657 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5658 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5659 else
5660 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5661 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005662 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005664 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005665 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005666 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005667 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5668 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Steve French50c2f752007-07-13 00:33:32 +00005670 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 since file handle passed in no longer valid */
5672
5673 return rc;
5674}
5675
Jeff Layton6d22f092008-09-23 11:48:35 -04005676int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005677CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005678 bool delete_file, __u16 fid, __u32 pid_of_opener)
5679{
5680 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5681 char *data_offset;
5682 int rc = 0;
5683 __u16 params, param_offset, offset, byte_count, count;
5684
Joe Perchesf96637b2013-05-04 22:12:25 -05005685 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5687
5688 if (rc)
5689 return rc;
5690
5691 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5692 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5693
5694 params = 6;
5695 pSMB->MaxSetupCount = 0;
5696 pSMB->Reserved = 0;
5697 pSMB->Flags = 0;
5698 pSMB->Timeout = 0;
5699 pSMB->Reserved2 = 0;
5700 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5701 offset = param_offset + params;
5702
5703 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5704
5705 count = 1;
5706 pSMB->MaxParameterCount = cpu_to_le16(2);
5707 /* BB find max SMB PDU from sess */
5708 pSMB->MaxDataCount = cpu_to_le16(1000);
5709 pSMB->SetupCount = 1;
5710 pSMB->Reserved3 = 0;
5711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5712 byte_count = 3 /* pad */ + params + count;
5713 pSMB->DataCount = cpu_to_le16(count);
5714 pSMB->ParameterCount = cpu_to_le16(params);
5715 pSMB->TotalDataCount = pSMB->DataCount;
5716 pSMB->TotalParameterCount = pSMB->ParameterCount;
5717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5718 pSMB->DataOffset = cpu_to_le16(offset);
5719 pSMB->Fid = fid;
5720 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5721 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005722 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005723 pSMB->ByteCount = cpu_to_le16(byte_count);
5724 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005725 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005726 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005727 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005728
5729 return rc;
5730}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731
5732int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005733CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005734 const char *fileName, const FILE_BASIC_INFO *data,
5735 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736{
5737 TRANSACTION2_SPI_REQ *pSMB = NULL;
5738 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5739 int name_len;
5740 int rc = 0;
5741 int bytes_returned = 0;
5742 char *data_offset;
5743 __u16 params, param_offset, offset, byte_count, count;
5744
Joe Perchesf96637b2013-05-04 22:12:25 -05005745 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746
5747SetTimesRetry:
5748 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5749 (void **) &pSMBr);
5750 if (rc)
5751 return rc;
5752
5753 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5754 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005755 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5756 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 name_len++; /* trailing null */
5758 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005759 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760 name_len = strnlen(fileName, PATH_MAX);
5761 name_len++; /* trailing null */
5762 strncpy(pSMB->FileName, fileName, name_len);
5763 }
5764
5765 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005766 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005768 /* BB find max SMB PDU from sess structure BB */
5769 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 pSMB->MaxSetupCount = 0;
5771 pSMB->Reserved = 0;
5772 pSMB->Flags = 0;
5773 pSMB->Timeout = 0;
5774 pSMB->Reserved2 = 0;
5775 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005776 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 offset = param_offset + params;
5778 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5779 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5780 pSMB->DataOffset = cpu_to_le16(offset);
5781 pSMB->SetupCount = 1;
5782 pSMB->Reserved3 = 0;
5783 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5784 byte_count = 3 /* pad */ + params + count;
5785
5786 pSMB->DataCount = cpu_to_le16(count);
5787 pSMB->ParameterCount = cpu_to_le16(params);
5788 pSMB->TotalDataCount = pSMB->DataCount;
5789 pSMB->TotalParameterCount = pSMB->ParameterCount;
5790 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5791 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5792 else
5793 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5794 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005795 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005796 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 pSMB->ByteCount = cpu_to_le16(byte_count);
5798 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5799 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005800 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005801 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
5803 cifs_buf_release(pSMB);
5804
5805 if (rc == -EAGAIN)
5806 goto SetTimesRetry;
5807
5808 return rc;
5809}
5810
5811/* Can not be used to set time stamps yet (due to old DOS time format) */
5812/* Can be used to set attributes */
5813#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5814 handling it anyway and NT4 was what we thought it would be needed for
5815 Do not delete it until we prove whether needed for Win9x though */
5816int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005817CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 __u16 dos_attrs, const struct nls_table *nls_codepage)
5819{
5820 SETATTR_REQ *pSMB = NULL;
5821 SETATTR_RSP *pSMBr = NULL;
5822 int rc = 0;
5823 int bytes_returned;
5824 int name_len;
5825
Joe Perchesf96637b2013-05-04 22:12:25 -05005826 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827
5828SetAttrLgcyRetry:
5829 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5830 (void **) &pSMBr);
5831 if (rc)
5832 return rc;
5833
5834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5835 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005836 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5837 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 name_len++; /* trailing null */
5839 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005840 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 name_len = strnlen(fileName, PATH_MAX);
5842 name_len++; /* trailing null */
5843 strncpy(pSMB->fileName, fileName, name_len);
5844 }
5845 pSMB->attr = cpu_to_le16(dos_attrs);
5846 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005847 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5850 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005851 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005852 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853
5854 cifs_buf_release(pSMB);
5855
5856 if (rc == -EAGAIN)
5857 goto SetAttrLgcyRetry;
5858
5859 return rc;
5860}
5861#endif /* temporarily unneeded SetAttr legacy function */
5862
Jeff Layton654cf142009-07-09 20:02:49 -04005863static void
5864cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5865 const struct cifs_unix_set_info_args *args)
5866{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005867 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005868 u64 mode = args->mode;
5869
Eric W. Biederman49418b22013-02-06 00:57:56 -08005870 if (uid_valid(args->uid))
5871 uid = from_kuid(&init_user_ns, args->uid);
5872 if (gid_valid(args->gid))
5873 gid = from_kgid(&init_user_ns, args->gid);
5874
Jeff Layton654cf142009-07-09 20:02:49 -04005875 /*
5876 * Samba server ignores set of file size to zero due to bugs in some
5877 * older clients, but we should be precise - we use SetFileSize to
5878 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005879 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005880 * zero instead of -1 here
5881 */
5882 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5883 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5884 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5885 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5886 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005887 data_offset->Uid = cpu_to_le64(uid);
5888 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005889 /* better to leave device as zero when it is */
5890 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5891 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5892 data_offset->Permissions = cpu_to_le64(mode);
5893
5894 if (S_ISREG(mode))
5895 data_offset->Type = cpu_to_le32(UNIX_FILE);
5896 else if (S_ISDIR(mode))
5897 data_offset->Type = cpu_to_le32(UNIX_DIR);
5898 else if (S_ISLNK(mode))
5899 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5900 else if (S_ISCHR(mode))
5901 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5902 else if (S_ISBLK(mode))
5903 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5904 else if (S_ISFIFO(mode))
5905 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5906 else if (S_ISSOCK(mode))
5907 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5908}
5909
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005911CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005912 const struct cifs_unix_set_info_args *args,
5913 u16 fid, u32 pid_of_opener)
5914{
5915 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005916 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005917 int rc = 0;
5918 u16 params, param_offset, offset, byte_count, count;
5919
Joe Perchesf96637b2013-05-04 22:12:25 -05005920 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005921 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5922
5923 if (rc)
5924 return rc;
5925
5926 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5927 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5928
5929 params = 6;
5930 pSMB->MaxSetupCount = 0;
5931 pSMB->Reserved = 0;
5932 pSMB->Flags = 0;
5933 pSMB->Timeout = 0;
5934 pSMB->Reserved2 = 0;
5935 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5936 offset = param_offset + params;
5937
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005938 data_offset = (char *)pSMB +
5939 offsetof(struct smb_hdr, Protocol) + offset;
5940
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005941 count = sizeof(FILE_UNIX_BASIC_INFO);
5942
5943 pSMB->MaxParameterCount = cpu_to_le16(2);
5944 /* BB find max SMB PDU from sess */
5945 pSMB->MaxDataCount = cpu_to_le16(1000);
5946 pSMB->SetupCount = 1;
5947 pSMB->Reserved3 = 0;
5948 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5949 byte_count = 3 /* pad */ + params + count;
5950 pSMB->DataCount = cpu_to_le16(count);
5951 pSMB->ParameterCount = cpu_to_le16(params);
5952 pSMB->TotalDataCount = pSMB->DataCount;
5953 pSMB->TotalParameterCount = pSMB->ParameterCount;
5954 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5955 pSMB->DataOffset = cpu_to_le16(offset);
5956 pSMB->Fid = fid;
5957 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5958 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005959 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005960 pSMB->ByteCount = cpu_to_le16(byte_count);
5961
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005962 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005963
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005964 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005965 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005966 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5967 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005968
5969 /* Note: On -EAGAIN error only caller can retry on handle based calls
5970 since file handle passed in no longer valid */
5971
5972 return rc;
5973}
5974
5975int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005976CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005977 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005978 const struct cifs_unix_set_info_args *args,
5979 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980{
5981 TRANSACTION2_SPI_REQ *pSMB = NULL;
5982 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5983 int name_len;
5984 int rc = 0;
5985 int bytes_returned = 0;
5986 FILE_UNIX_BASIC_INFO *data_offset;
5987 __u16 params, param_offset, offset, count, byte_count;
5988
Joe Perchesf96637b2013-05-04 22:12:25 -05005989 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990setPermsRetry:
5991 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5992 (void **) &pSMBr);
5993 if (rc)
5994 return rc;
5995
5996 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5997 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005998 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005999 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 name_len++; /* trailing null */
6001 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006002 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006003 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006005 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006 }
6007
6008 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006009 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006011 /* BB find max SMB PDU from sess structure BB */
6012 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013 pSMB->MaxSetupCount = 0;
6014 pSMB->Reserved = 0;
6015 pSMB->Flags = 0;
6016 pSMB->Timeout = 0;
6017 pSMB->Reserved2 = 0;
6018 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006019 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 offset = param_offset + params;
6021 data_offset =
6022 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6023 offset);
6024 memset(data_offset, 0, count);
6025 pSMB->DataOffset = cpu_to_le16(offset);
6026 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6027 pSMB->SetupCount = 1;
6028 pSMB->Reserved3 = 0;
6029 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6030 byte_count = 3 /* pad */ + params + count;
6031 pSMB->ParameterCount = cpu_to_le16(params);
6032 pSMB->DataCount = cpu_to_le16(count);
6033 pSMB->TotalParameterCount = pSMB->ParameterCount;
6034 pSMB->TotalDataCount = pSMB->DataCount;
6035 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6036 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006037 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006038
Jeff Layton654cf142009-07-09 20:02:49 -04006039 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040
6041 pSMB->ByteCount = cpu_to_le16(byte_count);
6042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006044 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006045 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046
Steve French0d817bc2008-05-22 02:02:03 +00006047 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 if (rc == -EAGAIN)
6049 goto setPermsRetry;
6050 return rc;
6051}
6052
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006054/*
6055 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6056 * function used by listxattr and getxattr type calls. When ea_name is set,
6057 * it looks for that attribute name and stuffs that value into the EAData
6058 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6059 * buffer. In both cases, the return value is either the length of the
6060 * resulting data or a negative error code. If EAData is a NULL pointer then
6061 * the data isn't copied to it, but the length is returned.
6062 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006064CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006065 const unsigned char *searchName, const unsigned char *ea_name,
6066 char *EAData, size_t buf_size,
6067 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068{
6069 /* BB assumes one setup word */
6070 TRANSACTION2_QPI_REQ *pSMB = NULL;
6071 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6072 int rc = 0;
6073 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006074 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006075 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006076 struct fea *temp_fea;
6077 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006078 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006079 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006080 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Joe Perchesf96637b2013-05-04 22:12:25 -05006082 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083QAllEAsRetry:
6084 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6085 (void **) &pSMBr);
6086 if (rc)
6087 return rc;
6088
6089 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006090 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006091 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6092 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006093 list_len++; /* trailing null */
6094 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006096 list_len = strnlen(searchName, PATH_MAX);
6097 list_len++; /* trailing null */
6098 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099 }
6100
Jeff Layton6e462b92010-02-10 16:18:26 -05006101 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 pSMB->TotalDataCount = 0;
6103 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006104 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006105 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 pSMB->MaxSetupCount = 0;
6107 pSMB->Reserved = 0;
6108 pSMB->Flags = 0;
6109 pSMB->Timeout = 0;
6110 pSMB->Reserved2 = 0;
6111 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006112 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113 pSMB->DataCount = 0;
6114 pSMB->DataOffset = 0;
6115 pSMB->SetupCount = 1;
6116 pSMB->Reserved3 = 0;
6117 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6118 byte_count = params + 1 /* pad */ ;
6119 pSMB->TotalParameterCount = cpu_to_le16(params);
6120 pSMB->ParameterCount = pSMB->TotalParameterCount;
6121 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6122 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006123 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 pSMB->ByteCount = cpu_to_le16(byte_count);
6125
6126 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6127 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6128 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006129 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006130 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006132
6133
6134 /* BB also check enough total bytes returned */
6135 /* BB we need to improve the validity checking
6136 of these trans2 responses */
6137
6138 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006139 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006140 rc = -EIO; /* bad smb */
6141 goto QAllEAsOut;
6142 }
6143
6144 /* check that length of list is not more than bcc */
6145 /* check that each entry does not go beyond length
6146 of list */
6147 /* check that each element of each entry does not
6148 go beyond end of list */
6149 /* validate_trans2_offsets() */
6150 /* BB check if start of smb + data_offset > &bcc+ bcc */
6151
6152 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6153 ea_response_data = (struct fealist *)
6154 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6155
Jeff Layton6e462b92010-02-10 16:18:26 -05006156 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006157 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006158 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006159 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006160 goto QAllEAsOut;
6161 }
6162
Jeff Layton0cd126b2010-02-10 16:18:26 -05006163 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006164 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006165 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006166 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006167 rc = -EIO;
6168 goto QAllEAsOut;
6169 }
6170
Jeff Laytonf0d38682010-02-10 16:18:26 -05006171 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006172 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006173 temp_fea = ea_response_data->list;
6174 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006175 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006176 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006177 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006178
Jeff Layton6e462b92010-02-10 16:18:26 -05006179 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006181 /* make sure we can read name_len and value_len */
6182 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006183 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006184 rc = -EIO;
6185 goto QAllEAsOut;
6186 }
6187
6188 name_len = temp_fea->name_len;
6189 value_len = le16_to_cpu(temp_fea->value_len);
6190 list_len -= name_len + 1 + value_len;
6191 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006192 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006193 rc = -EIO;
6194 goto QAllEAsOut;
6195 }
6196
Jeff Layton31c05192010-02-10 16:18:26 -05006197 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006198 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006199 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006200 temp_ptr += name_len + 1;
6201 rc = value_len;
6202 if (buf_size == 0)
6203 goto QAllEAsOut;
6204 if ((size_t)value_len > buf_size) {
6205 rc = -ERANGE;
6206 goto QAllEAsOut;
6207 }
6208 memcpy(EAData, temp_ptr, value_len);
6209 goto QAllEAsOut;
6210 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006211 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006212 /* account for prefix user. and trailing null */
6213 rc += (5 + 1 + name_len);
6214 if (rc < (int) buf_size) {
6215 memcpy(EAData, "user.", 5);
6216 EAData += 5;
6217 memcpy(EAData, temp_ptr, name_len);
6218 EAData += name_len;
6219 /* null terminate name */
6220 *EAData = 0;
6221 ++EAData;
6222 } else if (buf_size == 0) {
6223 /* skip copy - calc size only */
6224 } else {
6225 /* stop before overrun buffer */
6226 rc = -ERANGE;
6227 break;
6228 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006229 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006230 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006231 temp_fea = (struct fea *)temp_ptr;
6232 }
6233
Jeff Layton31c05192010-02-10 16:18:26 -05006234 /* didn't find the named attribute */
6235 if (ea_name)
6236 rc = -ENODATA;
6237
Jeff Laytonf0d38682010-02-10 16:18:26 -05006238QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006239 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 if (rc == -EAGAIN)
6241 goto QAllEAsRetry;
6242
6243 return (ssize_t)rc;
6244}
6245
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006247CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6248 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006249 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6250 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251{
6252 struct smb_com_transaction2_spi_req *pSMB = NULL;
6253 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6254 struct fealist *parm_data;
6255 int name_len;
6256 int rc = 0;
6257 int bytes_returned = 0;
6258 __u16 params, param_offset, byte_count, offset, count;
6259
Joe Perchesf96637b2013-05-04 22:12:25 -05006260 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261SetEARetry:
6262 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6263 (void **) &pSMBr);
6264 if (rc)
6265 return rc;
6266
6267 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6268 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006269 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6270 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 name_len++; /* trailing null */
6272 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006273 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 name_len = strnlen(fileName, PATH_MAX);
6275 name_len++; /* trailing null */
6276 strncpy(pSMB->FileName, fileName, name_len);
6277 }
6278
6279 params = 6 + name_len;
6280
6281 /* done calculating parms using name_len of file name,
6282 now use name_len to calculate length of ea name
6283 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006284 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 name_len = 0;
6286 else
Steve French50c2f752007-07-13 00:33:32 +00006287 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006289 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006291 /* BB find max SMB PDU from sess */
6292 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 pSMB->MaxSetupCount = 0;
6294 pSMB->Reserved = 0;
6295 pSMB->Flags = 0;
6296 pSMB->Timeout = 0;
6297 pSMB->Reserved2 = 0;
6298 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006299 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300 offset = param_offset + params;
6301 pSMB->InformationLevel =
6302 cpu_to_le16(SMB_SET_FILE_EA);
6303
6304 parm_data =
6305 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6306 offset);
6307 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6308 pSMB->DataOffset = cpu_to_le16(offset);
6309 pSMB->SetupCount = 1;
6310 pSMB->Reserved3 = 0;
6311 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6312 byte_count = 3 /* pad */ + params + count;
6313 pSMB->DataCount = cpu_to_le16(count);
6314 parm_data->list_len = cpu_to_le32(count);
6315 parm_data->list[0].EA_flags = 0;
6316 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006317 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006319 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006320 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 parm_data->list[0].name[name_len] = 0;
6322 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6323 /* caller ensures that ea_value_len is less than 64K but
6324 we need to ensure that it fits within the smb */
6325
Steve French50c2f752007-07-13 00:33:32 +00006326 /*BB add length check to see if it would fit in
6327 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006328 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6329 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006330 memcpy(parm_data->list[0].name+name_len+1,
6331 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
6333 pSMB->TotalDataCount = pSMB->DataCount;
6334 pSMB->ParameterCount = cpu_to_le16(params);
6335 pSMB->TotalParameterCount = pSMB->ParameterCount;
6336 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006337 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 pSMB->ByteCount = cpu_to_le16(byte_count);
6339 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6340 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006341 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006342 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343
6344 cifs_buf_release(pSMB);
6345
6346 if (rc == -EAGAIN)
6347 goto SetEARetry;
6348
6349 return rc;
6350}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351#endif
Steve French0eff0e22011-02-24 05:39:23 +00006352
6353#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6354/*
6355 * Years ago the kernel added a "dnotify" function for Samba server,
6356 * to allow network clients (such as Windows) to display updated
6357 * lists of files in directory listings automatically when
6358 * files are added by one user when another user has the
6359 * same directory open on their desktop. The Linux cifs kernel
6360 * client hooked into the kernel side of this interface for
6361 * the same reason, but ironically when the VFS moved from
6362 * "dnotify" to "inotify" it became harder to plug in Linux
6363 * network file system clients (the most obvious use case
6364 * for notify interfaces is when multiple users can update
6365 * the contents of the same directory - exactly what network
6366 * file systems can do) although the server (Samba) could
6367 * still use it. For the short term we leave the worker
6368 * function ifdeffed out (below) until inotify is fixed
6369 * in the VFS to make it easier to plug in network file
6370 * system clients. If inotify turns out to be permanently
6371 * incompatible for network fs clients, we could instead simply
6372 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6373 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006374int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006375 const int notify_subdirs, const __u16 netfid,
6376 __u32 filter, struct file *pfile, int multishot,
6377 const struct nls_table *nls_codepage)
6378{
6379 int rc = 0;
6380 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6381 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6382 struct dir_notify_req *dnotify_req;
6383 int bytes_returned;
6384
Joe Perchesf96637b2013-05-04 22:12:25 -05006385 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006386 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6387 (void **) &pSMBr);
6388 if (rc)
6389 return rc;
6390
6391 pSMB->TotalParameterCount = 0 ;
6392 pSMB->TotalDataCount = 0;
6393 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006394 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006395 pSMB->MaxSetupCount = 4;
6396 pSMB->Reserved = 0;
6397 pSMB->ParameterOffset = 0;
6398 pSMB->DataCount = 0;
6399 pSMB->DataOffset = 0;
6400 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6401 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6402 pSMB->ParameterCount = pSMB->TotalParameterCount;
6403 if (notify_subdirs)
6404 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6405 pSMB->Reserved2 = 0;
6406 pSMB->CompletionFilter = cpu_to_le32(filter);
6407 pSMB->Fid = netfid; /* file handle always le */
6408 pSMB->ByteCount = 0;
6409
6410 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6411 (struct smb_hdr *)pSMBr, &bytes_returned,
6412 CIFS_ASYNC_OP);
6413 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006414 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006415 } else {
6416 /* Add file to outstanding requests */
6417 /* BB change to kmem cache alloc */
6418 dnotify_req = kmalloc(
6419 sizeof(struct dir_notify_req),
6420 GFP_KERNEL);
6421 if (dnotify_req) {
6422 dnotify_req->Pid = pSMB->hdr.Pid;
6423 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6424 dnotify_req->Mid = pSMB->hdr.Mid;
6425 dnotify_req->Tid = pSMB->hdr.Tid;
6426 dnotify_req->Uid = pSMB->hdr.Uid;
6427 dnotify_req->netfid = netfid;
6428 dnotify_req->pfile = pfile;
6429 dnotify_req->filter = filter;
6430 dnotify_req->multishot = multishot;
6431 spin_lock(&GlobalMid_Lock);
6432 list_add_tail(&dnotify_req->lhead,
6433 &GlobalDnotifyReqList);
6434 spin_unlock(&GlobalMid_Lock);
6435 } else
6436 rc = -ENOMEM;
6437 }
6438 cifs_buf_release(pSMB);
6439 return rc;
6440}
6441#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */