blob: 80ca6886a8166310635a1855da9b4e4204a14504 [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
421cifs_enable_signing(struct TCP_Server_Info *server, unsigned int secFlags)
422{
423 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
424 /* MUST_SIGN already includes the MAY_SIGN FLAG
425 so if this is zero it means that signing is disabled */
426 cifs_dbg(FYI, "Signing disabled\n");
427 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
428 cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
429 return -EOPNOTSUPP;
430 }
431 server->sec_mode &=
432 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
433 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
434 /* signing required */
435 cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
436 if ((server->sec_mode &
437 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
438 cifs_dbg(VFS, "signing required but server lacks support\n");
439 return -EOPNOTSUPP;
440 } else
441 server->sec_mode |= SECMODE_SIGN_REQUIRED;
442 } else {
443 /* signing optional ie CIFSSEC_MAY_SIGN */
444 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
445 server->sec_mode &=
446 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
447 }
448
449 return 0;
450}
451
Jeff Layton2190eca2013-05-26 07:00:57 -0400452#ifdef CONFIG_CIFS_WEAK_PW_HASH
453static int
454decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
455 unsigned int secFlags)
456{
457 __s16 tmp;
458 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
459
460 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
461 return -EOPNOTSUPP;
462
463 if ((secFlags & CIFSSEC_MAY_LANMAN) || (secFlags & CIFSSEC_MAY_PLNTXT))
464 server->secType = LANMAN;
465 else {
466 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
467 return -EOPNOTSUPP;
468 }
469 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
470 server->maxReq = min_t(unsigned int,
471 le16_to_cpu(rsp->MaxMpxCount),
472 cifs_max_pending);
473 set_credits(server, server->maxReq);
474 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
475 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
476 /* even though we do not use raw we might as well set this
477 accurately, in case we ever find a need for it */
478 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
479 server->max_rw = 0xFF00;
480 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
481 } else {
482 server->max_rw = 0;/* do not need to use raw anyway */
483 server->capabilities = CAP_MPX_MODE;
484 }
485 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
486 if (tmp == -1) {
487 /* OS/2 often does not set timezone therefore
488 * we must use server time to calc time zone.
489 * Could deviate slightly from the right zone.
490 * Smallest defined timezone difference is 15 minutes
491 * (i.e. Nepal). Rounding up/down is done to match
492 * this requirement.
493 */
494 int val, seconds, remain, result;
495 struct timespec ts, utc;
496 utc = CURRENT_TIME;
497 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
498 rsp->SrvTime.Time, 0);
499 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
500 (int)ts.tv_sec, (int)utc.tv_sec,
501 (int)(utc.tv_sec - ts.tv_sec));
502 val = (int)(utc.tv_sec - ts.tv_sec);
503 seconds = abs(val);
504 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
505 remain = seconds % MIN_TZ_ADJ;
506 if (remain >= (MIN_TZ_ADJ / 2))
507 result += MIN_TZ_ADJ;
508 if (val < 0)
509 result = -result;
510 server->timeAdj = result;
511 } else {
512 server->timeAdj = (int)tmp;
513 server->timeAdj *= 60; /* also in seconds */
514 }
515 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
516
517
518 /* BB get server time for time conversions and add
519 code to use it and timezone since this is not UTC */
520
521 if (rsp->EncryptionKeyLength ==
522 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
523 memcpy(server->cryptkey, rsp->EncryptionKey,
524 CIFS_CRYPTO_KEY_SIZE);
525 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
526 return -EIO; /* need cryptkey unless plain text */
527 }
528
529 cifs_dbg(FYI, "LANMAN negotiated\n");
530 return 0;
531}
532#else
533static inline int
534decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
535 unsigned int secFlags)
536{
537 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
538 return -EOPNOTSUPP;
539}
540#endif
541
Jeff Layton91934002013-05-26 07:00:58 -0400542static bool
543should_set_ext_sec_flag(unsigned int secFlags)
544{
545 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
546 return true;
547 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5)
548 return true;
549 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
550 return true;
551 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP)
552 return true;
553 return false;
554}
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400557CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
559 NEGOTIATE_REQ *pSMB;
560 NEGOTIATE_RSP *pSMBr;
561 int rc = 0;
562 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000563 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400564 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000566 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Jeff Layton3534b852013-05-24 07:41:01 -0400568 if (!server) {
569 WARN(1, "%s: server is NULL!\n", __func__);
570 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
Jeff Layton3534b852013-05-24 07:41:01 -0400572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
574 (void **) &pSMB, (void **) &pSMBr);
575 if (rc)
576 return rc;
Steve French750d1152006-06-27 06:28:30 +0000577
578 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000579 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000580 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000581 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400582 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000583
Joe Perchesf96637b2013-05-04 22:12:25 -0500584 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000585
Pavel Shilovsky88257362012-05-23 14:01:59 +0400586 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000587 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000588
Jeff Layton91934002013-05-26 07:00:58 -0400589 if (should_set_ext_sec_flag(secFlags)) {
590 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000591 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
592 }
Steve French50c2f752007-07-13 00:33:32 +0000593
Steve French39798772006-05-31 22:40:51 +0000594 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000595 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000596 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
597 count += strlen(protocols[i].name) + 1;
598 /* null at end of source and target buffers anyway */
599 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000600 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 pSMB->ByteCount = cpu_to_le16(count);
602
603 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000605 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000606 goto neg_err_exit;
607
Jeff Layton9bf67e52010-04-24 07:57:46 -0400608 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500609 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000610 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400611 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000612 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000613 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000614 could not negotiate a common dialect */
615 rc = -EOPNOTSUPP;
616 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000617 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400618 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton2190eca2013-05-26 07:00:57 -0400619 rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
Jeff Layton9ddec562013-05-26 07:00:58 -0400620 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000621 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000622 /* unknown wct */
623 rc = -EOPNOTSUPP;
624 goto neg_err_exit;
625 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400626 /* else wct == 17, NTLM or better */
627
Steve French96daf2b2011-05-27 04:34:02 +0000628 server->sec_mode = pSMBr->SecurityMode;
629 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500630 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000631
Steve French96daf2b2011-05-27 04:34:02 +0000632 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000633#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000634 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000635#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500636 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000637
Steve French790fe572007-07-07 19:25:05 +0000638 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000639 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000640 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000641 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000642 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000643 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000644 else if (secFlags & CIFSSEC_MAY_KRB5)
645 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000646 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000647 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000648 else if (secFlags & CIFSSEC_MAY_LANMAN)
649 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000650 else {
651 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500652 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000653 goto neg_err_exit;
654 }
655 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000656
Steve French254e55e2006-06-04 05:53:15 +0000657 /* one byte, so no need to convert this or EncryptionKeyLen from
658 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300659 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
660 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400661 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000662 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400663 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000664 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500665 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000666 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000667 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
668 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400669
Jeff Laytone598d1d82013-05-26 07:00:59 -0400670 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
671 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500672 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000673 CIFS_CRYPTO_KEY_SIZE);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400674 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000675 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Laytone598d1d82013-05-26 07:00:59 -0400676 (pSMBr->EncryptionKeyLength == 0)) {
677 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400678 rc = decode_ext_sec_blob(server, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400679 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000680 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400681 } else {
682 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000683 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400684 }
Steve French254e55e2006-06-04 05:53:15 +0000685
686signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400687 if (!rc)
688 rc = cifs_enable_signing(server, secFlags);
Steve French50c2f752007-07-13 00:33:32 +0000689neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700690 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000691
Joe Perchesf96637b2013-05-04 22:12:25 -0500692 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return rc;
694}
695
696int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400697CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
699 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Joe Perchesf96637b2013-05-04 22:12:25 -0500702 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500703
704 /* BB: do we need to check this? These should never be NULL. */
705 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
706 return -EIO;
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500709 * No need to return error on this operation if tid invalidated and
710 * closed on server already e.g. due to tcp session crashing. Also,
711 * the tcon is no longer on the list, so no need to take lock before
712 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 */
Steve French268875b2009-06-25 00:29:21 +0000714 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000715 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Steve French50c2f752007-07-13 00:33:32 +0000717 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700718 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500719 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return rc;
Steve French133672e2007-11-13 22:41:37 +0000721
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400722 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500724 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Steve French50c2f752007-07-13 00:33:32 +0000726 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500727 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 if (rc == -EAGAIN)
729 rc = 0;
730
731 return rc;
732}
733
Jeff Layton766fdbb2011-01-11 07:24:21 -0500734/*
735 * This is a no-op for now. We're not really interested in the reply, but
736 * rather in the fact that the server sent one and that server->lstrp
737 * gets updated.
738 *
739 * FIXME: maybe we should consider checking that the reply matches request?
740 */
741static void
742cifs_echo_callback(struct mid_q_entry *mid)
743{
744 struct TCP_Server_Info *server = mid->callback_data;
745
746 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400747 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748}
749
750int
751CIFSSMBEcho(struct TCP_Server_Info *server)
752{
753 ECHO_REQ *smb;
754 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400755 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700756 struct smb_rqst rqst = { .rq_iov = &iov,
757 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500758
Joe Perchesf96637b2013-05-04 22:12:25 -0500759 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500760
761 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
762 if (rc)
763 return rc;
764
765 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000766 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500767 smb->hdr.WordCount = 1;
768 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400769 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500770 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000771 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400772 iov.iov_base = smb;
773 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500774
Jeff Laytonfec344e2012-09-18 16:20:35 -0700775 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400776 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500777 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500778 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500779
780 cifs_small_buf_release(smb);
781
782 return rc;
783}
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400786CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 LOGOFF_ANDX_REQ *pSMB;
789 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Joe Perchesf96637b2013-05-04 22:12:25 -0500791 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500792
793 /*
794 * BB: do we need to check validity of ses and server? They should
795 * always be valid since we have an active reference. If not, that
796 * should probably be a BUG()
797 */
798 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 return -EIO;
800
Steve Frenchd7b619c2010-02-25 05:36:46 +0000801 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000802 if (ses->need_reconnect)
803 goto session_already_dead; /* no need to send SMBlogoff if uid
804 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
806 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000807 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return rc;
809 }
810
Pavel Shilovsky88257362012-05-23 14:01:59 +0400811 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700812
Steve French96daf2b2011-05-27 04:34:02 +0000813 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
815 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 pSMB->hdr.Uid = ses->Suid;
818
819 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400820 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000821session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000822 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000825 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 error */
827 if (rc == -EAGAIN)
828 rc = 0;
829 return rc;
830}
831
832int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400833CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
834 const char *fileName, __u16 type,
835 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000836{
837 TRANSACTION2_SPI_REQ *pSMB = NULL;
838 TRANSACTION2_SPI_RSP *pSMBr = NULL;
839 struct unlink_psx_rq *pRqD;
840 int name_len;
841 int rc = 0;
842 int bytes_returned = 0;
843 __u16 params, param_offset, offset, byte_count;
844
Joe Perchesf96637b2013-05-04 22:12:25 -0500845 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000846PsxDelete:
847 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
848 (void **) &pSMBr);
849 if (rc)
850 return rc;
851
852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
853 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600854 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
855 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000856 name_len++; /* trailing null */
857 name_len *= 2;
858 } else { /* BB add path length overrun check */
859 name_len = strnlen(fileName, PATH_MAX);
860 name_len++; /* trailing null */
861 strncpy(pSMB->FileName, fileName, name_len);
862 }
863
864 params = 6 + name_len;
865 pSMB->MaxParameterCount = cpu_to_le16(2);
866 pSMB->MaxDataCount = 0; /* BB double check this with jra */
867 pSMB->MaxSetupCount = 0;
868 pSMB->Reserved = 0;
869 pSMB->Flags = 0;
870 pSMB->Timeout = 0;
871 pSMB->Reserved2 = 0;
872 param_offset = offsetof(struct smb_com_transaction2_spi_req,
873 InformationLevel) - 4;
874 offset = param_offset + params;
875
876 /* Setup pointer to Request Data (inode type) */
877 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
878 pRqD->type = cpu_to_le16(type);
879 pSMB->ParameterOffset = cpu_to_le16(param_offset);
880 pSMB->DataOffset = cpu_to_le16(offset);
881 pSMB->SetupCount = 1;
882 pSMB->Reserved3 = 0;
883 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
884 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
885
886 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
887 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
888 pSMB->ParameterCount = cpu_to_le16(params);
889 pSMB->TotalParameterCount = pSMB->ParameterCount;
890 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
891 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000892 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000893 pSMB->ByteCount = cpu_to_le16(byte_count);
894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000896 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500897 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000898 cifs_buf_release(pSMB);
899
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400900 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000901
902 if (rc == -EAGAIN)
903 goto PsxDelete;
904
905 return rc;
906}
907
908int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700909CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
910 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 DELETE_FILE_REQ *pSMB = NULL;
913 DELETE_FILE_RSP *pSMBr = NULL;
914 int rc = 0;
915 int bytes_returned;
916 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700917 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919DelFileRetry:
920 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
921 (void **) &pSMBr);
922 if (rc)
923 return rc;
924
925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700926 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
927 PATH_MAX, cifs_sb->local_nls,
928 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 name_len++; /* trailing null */
930 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700931 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700932 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700934 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 }
936 pSMB->SearchAttributes =
937 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
938 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000939 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 pSMB->ByteCount = cpu_to_le16(name_len + 1);
941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400943 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000944 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500945 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 cifs_buf_release(pSMB);
948 if (rc == -EAGAIN)
949 goto DelFileRetry;
950
951 return rc;
952}
953
954int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400955CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
956 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957{
958 DELETE_DIRECTORY_REQ *pSMB = NULL;
959 DELETE_DIRECTORY_RSP *pSMBr = NULL;
960 int rc = 0;
961 int bytes_returned;
962 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400963 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Joe Perchesf96637b2013-05-04 22:12:25 -0500965 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966RmDirRetry:
967 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
968 (void **) &pSMBr);
969 if (rc)
970 return rc;
971
972 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400973 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
974 PATH_MAX, cifs_sb->local_nls,
975 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 name_len++; /* trailing null */
977 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700978 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400979 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400981 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
983
984 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000985 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 pSMB->ByteCount = cpu_to_le16(name_len + 1);
987 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
988 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400989 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000990 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500991 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 cifs_buf_release(pSMB);
994 if (rc == -EAGAIN)
995 goto RmDirRetry;
996 return rc;
997}
998
999int
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001000CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1001 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002{
1003 int rc = 0;
1004 CREATE_DIRECTORY_REQ *pSMB = NULL;
1005 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1006 int bytes_returned;
1007 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001008 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Joe Perchesf96637b2013-05-04 22:12:25 -05001010 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011MkDirRetry:
1012 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1013 (void **) &pSMBr);
1014 if (rc)
1015 return rc;
1016
1017 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001018 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001019 PATH_MAX, cifs_sb->local_nls,
1020 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 name_len++; /* trailing null */
1022 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001023 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 name_len = strnlen(name, PATH_MAX);
1025 name_len++; /* trailing null */
1026 strncpy(pSMB->DirName, name, name_len);
1027 }
1028
1029 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001030 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1032 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1033 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001034 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001035 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001036 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 cifs_buf_release(pSMB);
1039 if (rc == -EAGAIN)
1040 goto MkDirRetry;
1041 return rc;
1042}
1043
Steve French2dd29d32007-04-23 22:07:35 +00001044int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001045CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1046 __u32 posix_flags, __u64 mode, __u16 *netfid,
1047 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1048 const char *name, const struct nls_table *nls_codepage,
1049 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001050{
1051 TRANSACTION2_SPI_REQ *pSMB = NULL;
1052 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1053 int name_len;
1054 int rc = 0;
1055 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001056 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001057 OPEN_PSX_REQ *pdata;
1058 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001059
Joe Perchesf96637b2013-05-04 22:12:25 -05001060 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001061PsxCreat:
1062 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1063 (void **) &pSMBr);
1064 if (rc)
1065 return rc;
1066
1067 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1068 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001069 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1070 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001071 name_len++; /* trailing null */
1072 name_len *= 2;
1073 } else { /* BB improve the check for buffer overruns BB */
1074 name_len = strnlen(name, PATH_MAX);
1075 name_len++; /* trailing null */
1076 strncpy(pSMB->FileName, name, name_len);
1077 }
1078
1079 params = 6 + name_len;
1080 count = sizeof(OPEN_PSX_REQ);
1081 pSMB->MaxParameterCount = cpu_to_le16(2);
1082 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1083 pSMB->MaxSetupCount = 0;
1084 pSMB->Reserved = 0;
1085 pSMB->Flags = 0;
1086 pSMB->Timeout = 0;
1087 pSMB->Reserved2 = 0;
1088 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001089 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001090 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001091 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001092 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001093 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001094 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001095 pdata->OpenFlags = cpu_to_le32(*pOplock);
1096 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1097 pSMB->DataOffset = cpu_to_le16(offset);
1098 pSMB->SetupCount = 1;
1099 pSMB->Reserved3 = 0;
1100 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1101 byte_count = 3 /* pad */ + params + count;
1102
1103 pSMB->DataCount = cpu_to_le16(count);
1104 pSMB->ParameterCount = cpu_to_le16(params);
1105 pSMB->TotalDataCount = pSMB->DataCount;
1106 pSMB->TotalParameterCount = pSMB->ParameterCount;
1107 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1108 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001109 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001110 pSMB->ByteCount = cpu_to_le16(byte_count);
1111 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1112 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1113 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001114 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001115 goto psx_create_err;
1116 }
1117
Joe Perchesf96637b2013-05-04 22:12:25 -05001118 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001119 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1120
Jeff Layton820a8032011-05-04 08:05:26 -04001121 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001122 rc = -EIO; /* bad smb */
1123 goto psx_create_err;
1124 }
1125
1126 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001127 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001128 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001129
Steve French2dd29d32007-04-23 22:07:35 +00001130 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001131 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001132 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1133 /* Let caller know file was created so we can set the mode. */
1134 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001135 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001136 *pOplock |= CIFS_CREATE_ACTION;
1137 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001138 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1139 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001140 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001141 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001142 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001143 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001144 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001145 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001146 goto psx_create_err;
1147 }
Steve French50c2f752007-07-13 00:33:32 +00001148 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001149 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001150 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001151 }
Steve French2dd29d32007-04-23 22:07:35 +00001152
1153psx_create_err:
1154 cifs_buf_release(pSMB);
1155
Steve French65bc98b2009-07-10 15:27:25 +00001156 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001157 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001158 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001159 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001160
1161 if (rc == -EAGAIN)
1162 goto PsxCreat;
1163
Steve French50c2f752007-07-13 00:33:32 +00001164 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001165}
1166
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167static __u16 convert_disposition(int disposition)
1168{
1169 __u16 ofun = 0;
1170
1171 switch (disposition) {
1172 case FILE_SUPERSEDE:
1173 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1174 break;
1175 case FILE_OPEN:
1176 ofun = SMBOPEN_OAPPEND;
1177 break;
1178 case FILE_CREATE:
1179 ofun = SMBOPEN_OCREATE;
1180 break;
1181 case FILE_OPEN_IF:
1182 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1183 break;
1184 case FILE_OVERWRITE:
1185 ofun = SMBOPEN_OTRUNC;
1186 break;
1187 case FILE_OVERWRITE_IF:
1188 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1189 break;
1190 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001191 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001192 ofun = SMBOPEN_OAPPEND; /* regular open */
1193 }
1194 return ofun;
1195}
1196
Jeff Layton35fc37d2008-05-14 10:22:03 -07001197static int
1198access_flags_to_smbopen_mode(const int access_flags)
1199{
1200 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1201
1202 if (masked_flags == GENERIC_READ)
1203 return SMBOPEN_READ;
1204 else if (masked_flags == GENERIC_WRITE)
1205 return SMBOPEN_WRITE;
1206
1207 /* just go for read/write */
1208 return SMBOPEN_READWRITE;
1209}
1210
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001212SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001214 const int access_flags, const int create_options, __u16 *netfid,
1215 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 const struct nls_table *nls_codepage, int remap)
1217{
1218 int rc = -EACCES;
1219 OPENX_REQ *pSMB = NULL;
1220 OPENX_RSP *pSMBr = NULL;
1221 int bytes_returned;
1222 int name_len;
1223 __u16 count;
1224
1225OldOpenRetry:
1226 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1227 (void **) &pSMBr);
1228 if (rc)
1229 return rc;
1230
1231 pSMB->AndXCommand = 0xFF; /* none */
1232
1233 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1234 count = 1; /* account for one byte pad to word boundary */
1235 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001236 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1237 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238 name_len++; /* trailing null */
1239 name_len *= 2;
1240 } else { /* BB improve check for buffer overruns BB */
1241 count = 0; /* no pad */
1242 name_len = strnlen(fileName, PATH_MAX);
1243 name_len++; /* trailing null */
1244 strncpy(pSMB->fileName, fileName, name_len);
1245 }
1246 if (*pOplock & REQ_OPLOCK)
1247 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001248 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001250
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001252 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1254 /* set file as system file if special file such
1255 as fifo and server expecting SFU style and
1256 no Unix extensions */
1257
Steve French790fe572007-07-07 19:25:05 +00001258 if (create_options & CREATE_OPTION_SPECIAL)
1259 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001260 else /* BB FIXME BB */
1261 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262
Jeff Layton67750fb2008-05-09 22:28:02 +00001263 if (create_options & CREATE_OPTION_READONLY)
1264 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265
1266 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001267/* pSMB->CreateOptions = cpu_to_le32(create_options &
1268 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001270
1271 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001272 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001274 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275
1276 pSMB->ByteCount = cpu_to_le16(count);
1277 /* long_op set to 1 to allow for oplock break timeouts */
1278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001279 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001280 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001282 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 } else {
1284 /* BB verify if wct == 15 */
1285
Steve French582d21e2008-05-13 04:54:12 +00001286/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001287
1288 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1289 /* Let caller know file was created so we can set the mode. */
1290 /* Do we care about the CreateAction in any other cases? */
1291 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001292/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001293 *pOplock |= CIFS_CREATE_ACTION; */
1294 /* BB FIXME END */
1295
Steve French790fe572007-07-07 19:25:05 +00001296 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1298 pfile_info->LastAccessTime = 0; /* BB fixme */
1299 pfile_info->LastWriteTime = 0; /* BB fixme */
1300 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001301 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001302 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001304 pfile_info->AllocationSize =
1305 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1306 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001307 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001308 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001309 }
1310 }
1311
1312 cifs_buf_release(pSMB);
1313 if (rc == -EAGAIN)
1314 goto OldOpenRetry;
1315 return rc;
1316}
1317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001319CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001321 const int access_flags, const int create_options, __u16 *netfid,
1322 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001323 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324{
1325 int rc = -EACCES;
1326 OPEN_REQ *pSMB = NULL;
1327 OPEN_RSP *pSMBr = NULL;
1328 int bytes_returned;
1329 int name_len;
1330 __u16 count;
1331
1332openRetry:
1333 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1334 (void **) &pSMBr);
1335 if (rc)
1336 return rc;
1337
1338 pSMB->AndXCommand = 0xFF; /* none */
1339
1340 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1341 count = 1; /* account for one byte pad to word boundary */
1342 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001343 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1344 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 name_len++; /* trailing null */
1346 name_len *= 2;
1347 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001348 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 count = 0; /* no pad */
1350 name_len = strnlen(fileName, PATH_MAX);
1351 name_len++; /* trailing null */
1352 pSMB->NameLength = cpu_to_le16(name_len);
1353 strncpy(pSMB->fileName, fileName, name_len);
1354 }
1355 if (*pOplock & REQ_OPLOCK)
1356 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001357 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1360 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001361 /* set file as system file if special file such
1362 as fifo and server expecting SFU style and
1363 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001364 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001365 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1366 else
1367 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001368
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 /* XP does not handle ATTR_POSIX_SEMANTICS */
1370 /* but it helps speed up case sensitive checks for other
1371 servers such as Samba */
1372 if (tcon->ses->capabilities & CAP_UNIX)
1373 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1374
Jeff Layton67750fb2008-05-09 22:28:02 +00001375 if (create_options & CREATE_OPTION_READONLY)
1376 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1379 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001380 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001381 /* BB Expirement with various impersonation levels and verify */
1382 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 pSMB->SecurityFlags =
1384 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1385
1386 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001387 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389 pSMB->ByteCount = cpu_to_le16(count);
1390 /* long_op set to 1 to allow for oplock break timeouts */
1391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001392 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001393 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001395 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 } else {
Steve French09d1db52005-04-28 22:41:08 -07001397 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1399 /* Let caller know file was created so we can set the mode. */
1400 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001401 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001402 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001403 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001404 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1405 36 /* CreationTime to Attributes */);
1406 /* the file_info buf is endian converted by caller */
1407 pfile_info->AllocationSize = pSMBr->AllocationSize;
1408 pfile_info->EndOfFile = pSMBr->EndOfFile;
1409 pfile_info->NumberOfLinks = cpu_to_le32(1);
1410 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001413
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 cifs_buf_release(pSMB);
1415 if (rc == -EAGAIN)
1416 goto openRetry;
1417 return rc;
1418}
1419
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001420/*
1421 * Discard any remaining data in the current SMB. To do this, we borrow the
1422 * current bigbuf.
1423 */
1424static int
1425cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1426{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001427 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001428 int remaining = rfclen + 4 - server->total_read;
1429 struct cifs_readdata *rdata = mid->callback_data;
1430
1431 while (remaining > 0) {
1432 int length;
1433
1434 length = cifs_read_from_socket(server, server->bigbuf,
1435 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001436 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001437 if (length < 0)
1438 return length;
1439 server->total_read += length;
1440 remaining -= length;
1441 }
1442
1443 dequeue_mid(mid, rdata->result);
1444 return 0;
1445}
1446
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001447int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1449{
1450 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001451 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001452 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001453 char *buf = server->smallbuf;
1454 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001455
Joe Perchesf96637b2013-05-04 22:12:25 -05001456 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1457 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001458
1459 /*
1460 * read the rest of READ_RSP header (sans Data array), or whatever we
1461 * can if there's not enough data. At this point, we've read down to
1462 * the Mid.
1463 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001464 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001465 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001466
Jeff Layton58195752012-09-19 06:22:34 -07001467 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1468 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001469
Jeff Layton58195752012-09-19 06:22:34 -07001470 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001471 if (length < 0)
1472 return length;
1473 server->total_read += length;
1474
1475 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001476 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001477 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001478 cifs_dbg(FYI, "%s: server returned error %d\n",
1479 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001480 return cifs_readv_discard(server, mid);
1481 }
1482
1483 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001484 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001485 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1486 __func__, server->total_read,
1487 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001488 rdata->result = -EIO;
1489 return cifs_readv_discard(server, mid);
1490 }
1491
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001492 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001493 if (data_offset < server->total_read) {
1494 /*
1495 * win2k8 sometimes sends an offset of 0 when the read
1496 * is beyond the EOF. Treat it as if the data starts just after
1497 * the header.
1498 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001499 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1500 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001501 data_offset = server->total_read;
1502 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1503 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001504 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1505 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506 rdata->result = -EIO;
1507 return cifs_readv_discard(server, mid);
1508 }
1509
Joe Perchesf96637b2013-05-04 22:12:25 -05001510 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1511 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001512
1513 len = data_offset - server->total_read;
1514 if (len > 0) {
1515 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001516 rdata->iov.iov_base = buf + server->total_read;
1517 rdata->iov.iov_len = len;
1518 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519 if (length < 0)
1520 return length;
1521 server->total_read += length;
1522 }
1523
1524 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001525 rdata->iov.iov_base = buf;
1526 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001527 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1528 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529
1530 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001531 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001532 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001533 /* data_len is corrupt -- discard frame */
1534 rdata->result = -EIO;
1535 return cifs_readv_discard(server, mid);
1536 }
1537
Jeff Layton8321fec2012-09-19 06:22:32 -07001538 length = rdata->read_into_pages(server, rdata, data_len);
1539 if (length < 0)
1540 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541
Jeff Layton8321fec2012-09-19 06:22:32 -07001542 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543 rdata->bytes = length;
1544
Joe Perchesf96637b2013-05-04 22:12:25 -05001545 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1546 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547
1548 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001549 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001550 return cifs_readv_discard(server, mid);
1551
1552 dequeue_mid(mid, false);
1553 return length;
1554}
1555
1556static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557cifs_readv_callback(struct mid_q_entry *mid)
1558{
1559 struct cifs_readdata *rdata = mid->callback_data;
1560 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1561 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001562 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1563 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001564 .rq_pages = rdata->pages,
1565 .rq_npages = rdata->nr_pages,
1566 .rq_pagesz = rdata->pagesz,
1567 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001568
Joe Perchesf96637b2013-05-04 22:12:25 -05001569 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1570 __func__, mid->mid, mid->mid_state, rdata->result,
1571 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001573 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001574 case MID_RESPONSE_RECEIVED:
1575 /* result already set, check signature */
1576 if (server->sec_mode &
1577 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff2012-08-03 09:42:45 -05001578 int rc = 0;
1579
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001580 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001581 mid->sequence_number);
Steve French985e4ff2012-08-03 09:42:45 -05001582 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001583 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1584 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585 }
1586 /* FIXME: should this be counted toward the initiating task? */
1587 task_io_account_read(rdata->bytes);
1588 cifs_stats_bytes_read(tcon, rdata->bytes);
1589 break;
1590 case MID_REQUEST_SUBMITTED:
1591 case MID_RETRY_NEEDED:
1592 rdata->result = -EAGAIN;
1593 break;
1594 default:
1595 rdata->result = -EIO;
1596 }
1597
Jeff Laytonda472fc2012-03-23 14:40:53 -04001598 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001599 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001600 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001601}
1602
1603/* cifs_async_readv - send an async write, and set up mid to handle result */
1604int
1605cifs_async_readv(struct cifs_readdata *rdata)
1606{
1607 int rc;
1608 READ_REQ *smb = NULL;
1609 int wct;
1610 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001611 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001612 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001613
Joe Perchesf96637b2013-05-04 22:12:25 -05001614 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1615 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001616
1617 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1618 wct = 12;
1619 else {
1620 wct = 10; /* old style read */
1621 if ((rdata->offset >> 32) > 0) {
1622 /* can not handle this big offset for old */
1623 return -EIO;
1624 }
1625 }
1626
1627 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1628 if (rc)
1629 return rc;
1630
1631 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1632 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1633
1634 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001635 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001636 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1637 if (wct == 12)
1638 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1639 smb->Remaining = 0;
1640 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1641 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1642 if (wct == 12)
1643 smb->ByteCount = 0;
1644 else {
1645 /* old style read */
1646 struct smb_com_readx_req *smbr =
1647 (struct smb_com_readx_req *)smb;
1648 smbr->ByteCount = 0;
1649 }
1650
1651 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001652 rdata->iov.iov_base = smb;
1653 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001654
Jeff Layton6993f742012-05-16 07:13:17 -04001655 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001656 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1657 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658
1659 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001660 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001661 else
1662 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001663
1664 cifs_small_buf_release(smb);
1665 return rc;
1666}
1667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001669CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1670 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671{
1672 int rc = -EACCES;
1673 READ_REQ *pSMB = NULL;
1674 READ_RSP *pSMBr = NULL;
1675 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001676 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001677 int resp_buf_type = 0;
1678 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001679 __u32 pid = io_parms->pid;
1680 __u16 netfid = io_parms->netfid;
1681 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001682 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001683 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Joe Perchesf96637b2013-05-04 22:12:25 -05001685 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001686 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001687 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001688 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001689 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001690 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001691 /* can not handle this big offset for old */
1692 return -EIO;
1693 }
1694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001697 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 if (rc)
1699 return rc;
1700
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001701 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1702 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 /* tcon and ses pointer are checked in smb_init */
1705 if (tcon->ses->server == NULL)
1706 return -ECONNABORTED;
1707
Steve Frenchec637e32005-12-12 20:53:18 -08001708 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001710 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001711 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001712 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 pSMB->Remaining = 0;
1715 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1716 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001717 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001718 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1719 else {
1720 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001721 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001722 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001723 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001724 }
Steve Frenchec637e32005-12-12 20:53:18 -08001725
1726 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001727 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001728 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001729 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001730 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001731 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001733 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 } else {
1735 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1736 data_length = data_length << 16;
1737 data_length += le16_to_cpu(pSMBr->DataLength);
1738 *nbytes = data_length;
1739
1740 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001741 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001743 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001744 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 rc = -EIO;
1746 *nbytes = 0;
1747 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001748 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001749 le16_to_cpu(pSMBr->DataOffset);
1750/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001751 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001752 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001753 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001754 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001755 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 }
1757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
Steve French4b8f9302006-02-26 16:41:18 +00001759/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001760 if (*buf) {
1761 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001762 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001763 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001764 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001765 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001766 /* return buffer to caller to free */
1767 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001768 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001769 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001770 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001771 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001772 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001773
1774 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 since file handle passed in no longer valid */
1776 return rc;
1777}
1778
Steve Frenchec637e32005-12-12 20:53:18 -08001779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001781CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001782 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001783 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784{
1785 int rc = -EACCES;
1786 WRITE_REQ *pSMB = NULL;
1787 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001788 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 __u32 bytes_sent;
1790 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001791 __u32 pid = io_parms->pid;
1792 __u16 netfid = io_parms->netfid;
1793 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001794 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001795 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Steve Frencha24e2d72010-04-03 17:20:21 +00001797 *nbytes = 0;
1798
Joe Perchesf96637b2013-05-04 22:12:25 -05001799 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001800 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001801 return -ECONNABORTED;
1802
Steve French790fe572007-07-07 19:25:05 +00001803 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001804 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001805 else {
Steve French1c955182005-08-30 20:58:07 -07001806 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001807 if ((offset >> 32) > 0) {
1808 /* can not handle big offset for old srv */
1809 return -EIO;
1810 }
1811 }
Steve French1c955182005-08-30 20:58:07 -07001812
1813 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 (void **) &pSMBr);
1815 if (rc)
1816 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001817
1818 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1819 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 /* tcon and ses pointer are checked in smb_init */
1822 if (tcon->ses->server == NULL)
1823 return -ECONNABORTED;
1824
1825 pSMB->AndXCommand = 0xFF; /* none */
1826 pSMB->Fid = netfid;
1827 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001828 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001829 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001830
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 pSMB->Reserved = 0xFFFFFFFF;
1832 pSMB->WriteMode = 0;
1833 pSMB->Remaining = 0;
1834
Steve French50c2f752007-07-13 00:33:32 +00001835 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 can send more if LARGE_WRITE_X capability returned by the server and if
1837 our buffer is big enough or if we convert to iovecs on socket writes
1838 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001839 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1841 } else {
1842 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1843 & ~0xFF;
1844 }
1845
1846 if (bytes_sent > count)
1847 bytes_sent = count;
1848 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001849 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001850 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001851 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001852 else if (ubuf) {
1853 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 cifs_buf_release(pSMB);
1855 return -EFAULT;
1856 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001857 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 /* No buffer */
1859 cifs_buf_release(pSMB);
1860 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001861 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001862 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001863 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001864 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001865 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1868 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001869 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001870
Steve French790fe572007-07-07 19:25:05 +00001871 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001872 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001873 else { /* old style write has byte count 4 bytes earlier
1874 so 4 bytes pad */
1875 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001876 (struct smb_com_writex_req *)pSMB;
1877 pSMBW->ByteCount = cpu_to_le16(byte_count);
1878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1881 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001882 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001884 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 } else {
1886 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1887 *nbytes = (*nbytes) << 16;
1888 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301889
1890 /*
1891 * Mask off high 16 bits when bytes written as returned by the
1892 * server is greater than bytes requested by the client. Some
1893 * OS/2 servers are known to set incorrect CountHigh values.
1894 */
1895 if (*nbytes > count)
1896 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
1898
1899 cifs_buf_release(pSMB);
1900
Steve French50c2f752007-07-13 00:33:32 +00001901 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 since file handle passed in no longer valid */
1903
1904 return rc;
1905}
1906
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001907void
1908cifs_writedata_release(struct kref *refcount)
1909{
1910 struct cifs_writedata *wdata = container_of(refcount,
1911 struct cifs_writedata, refcount);
1912
1913 if (wdata->cfile)
1914 cifsFileInfo_put(wdata->cfile);
1915
1916 kfree(wdata);
1917}
1918
1919/*
1920 * Write failed with a retryable error. Resend the write request. It's also
1921 * possible that the page was redirtied so re-clean the page.
1922 */
1923static void
1924cifs_writev_requeue(struct cifs_writedata *wdata)
1925{
1926 int i, rc;
1927 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001928 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001929
1930 for (i = 0; i < wdata->nr_pages; i++) {
1931 lock_page(wdata->pages[i]);
1932 clear_page_dirty_for_io(wdata->pages[i]);
1933 }
1934
1935 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001936 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1937 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001938 } while (rc == -EAGAIN);
1939
1940 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001941 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001942 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001943 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001944 end_page_writeback(wdata->pages[i]);
1945 page_cache_release(wdata->pages[i]);
1946 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001947 }
1948
1949 mapping_set_error(inode->i_mapping, rc);
1950 kref_put(&wdata->refcount, cifs_writedata_release);
1951}
1952
Jeff Laytonc2e87642012-03-23 14:40:55 -04001953void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001954cifs_writev_complete(struct work_struct *work)
1955{
1956 struct cifs_writedata *wdata = container_of(work,
1957 struct cifs_writedata, work);
1958 struct inode *inode = wdata->cfile->dentry->d_inode;
1959 int i = 0;
1960
1961 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001962 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001963 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001964 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001965 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1966 wdata->bytes);
1967 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1968 return cifs_writev_requeue(wdata);
1969
1970 for (i = 0; i < wdata->nr_pages; i++) {
1971 struct page *page = wdata->pages[i];
1972 if (wdata->result == -EAGAIN)
1973 __set_page_dirty_nobuffers(page);
1974 else if (wdata->result < 0)
1975 SetPageError(page);
1976 end_page_writeback(page);
1977 page_cache_release(page);
1978 }
1979 if (wdata->result != -EAGAIN)
1980 mapping_set_error(inode->i_mapping, wdata->result);
1981 kref_put(&wdata->refcount, cifs_writedata_release);
1982}
1983
1984struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001985cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001986{
1987 struct cifs_writedata *wdata;
1988
1989 /* this would overflow */
1990 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001991 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001992 return NULL;
1993 }
1994
1995 /* writedata + number of page pointers */
1996 wdata = kzalloc(sizeof(*wdata) +
1997 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1998 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001999 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002000 INIT_LIST_HEAD(&wdata->list);
2001 init_completion(&wdata->done);
2002 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002003 }
2004 return wdata;
2005}
2006
2007/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002008 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002009 * workqueue completion task.
2010 */
2011static void
2012cifs_writev_callback(struct mid_q_entry *mid)
2013{
2014 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002015 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002016 unsigned int written;
2017 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2018
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002019 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002020 case MID_RESPONSE_RECEIVED:
2021 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2022 if (wdata->result != 0)
2023 break;
2024
2025 written = le16_to_cpu(smb->CountHigh);
2026 written <<= 16;
2027 written += le16_to_cpu(smb->Count);
2028 /*
2029 * Mask off high 16 bits when bytes written as returned
2030 * by the server is greater than bytes requested by the
2031 * client. OS/2 servers are known to set incorrect
2032 * CountHigh values.
2033 */
2034 if (written > wdata->bytes)
2035 written &= 0xFFFF;
2036
2037 if (written < wdata->bytes)
2038 wdata->result = -ENOSPC;
2039 else
2040 wdata->bytes = written;
2041 break;
2042 case MID_REQUEST_SUBMITTED:
2043 case MID_RETRY_NEEDED:
2044 wdata->result = -EAGAIN;
2045 break;
2046 default:
2047 wdata->result = -EIO;
2048 break;
2049 }
2050
Jeff Laytonda472fc2012-03-23 14:40:53 -04002051 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002053 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002054}
2055
2056/* cifs_async_writev - send an async write, and set up mid to handle result */
2057int
2058cifs_async_writev(struct cifs_writedata *wdata)
2059{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002060 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002061 WRITE_REQ *smb = NULL;
2062 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002063 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002064 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002065 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002066
2067 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2068 wct = 14;
2069 } else {
2070 wct = 12;
2071 if (wdata->offset >> 32 > 0) {
2072 /* can not handle big offset for old srv */
2073 return -EIO;
2074 }
2075 }
2076
2077 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2078 if (rc)
2079 goto async_writev_out;
2080
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002081 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2082 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002083
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002084 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002085 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002086 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2087 if (wct == 14)
2088 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2089 smb->Reserved = 0xFFFFFFFF;
2090 smb->WriteMode = 0;
2091 smb->Remaining = 0;
2092
2093 smb->DataOffset =
2094 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2095
2096 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002097 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2098 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099
Jeff Laytoneddb0792012-09-18 16:20:35 -07002100 rqst.rq_iov = &iov;
2101 rqst.rq_nvec = 1;
2102 rqst.rq_pages = wdata->pages;
2103 rqst.rq_npages = wdata->nr_pages;
2104 rqst.rq_pagesz = wdata->pagesz;
2105 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002106
Joe Perchesf96637b2013-05-04 22:12:25 -05002107 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2108 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002109
2110 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2111 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2112
2113 if (wct == 14) {
2114 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2115 put_bcc(wdata->bytes + 1, &smb->hdr);
2116 } else {
2117 /* wct == 12 */
2118 struct smb_com_writex_req *smbw =
2119 (struct smb_com_writex_req *)smb;
2120 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2121 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002122 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002123 }
2124
2125 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002126 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2127 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002128
2129 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002130 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002131 else
2132 kref_put(&wdata->refcount, cifs_writedata_release);
2133
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002134async_writev_out:
2135 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002136 return rc;
2137}
2138
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002139int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002140CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad722012-09-18 16:20:30 -07002141 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142{
2143 int rc = -EACCES;
2144 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002145 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002146 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002147 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002148 __u32 pid = io_parms->pid;
2149 __u16 netfid = io_parms->netfid;
2150 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002151 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002152 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002154 *nbytes = 0;
2155
Joe Perchesf96637b2013-05-04 22:12:25 -05002156 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002157
Steve French4c3130e2008-12-09 00:28:16 +00002158 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002159 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002160 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002161 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002162 if ((offset >> 32) > 0) {
2163 /* can not handle big offset for old srv */
2164 return -EIO;
2165 }
2166 }
Steve French8cc64c62005-10-03 13:49:43 -07002167 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 if (rc)
2169 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002170
2171 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2172 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* tcon and ses pointer are checked in smb_init */
2175 if (tcon->ses->server == NULL)
2176 return -ECONNABORTED;
2177
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002178 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 pSMB->Fid = netfid;
2180 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002181 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002182 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 pSMB->Reserved = 0xFFFFFFFF;
2184 pSMB->WriteMode = 0;
2185 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002186
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002188 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Steve French3e844692005-10-03 13:37:24 -07002190 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2191 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002192 /* header + 1 byte pad */
2193 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002194 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002195 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002196 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002197 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002198 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002199 pSMB->ByteCount = cpu_to_le16(count + 1);
2200 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002201 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002202 (struct smb_com_writex_req *)pSMB;
2203 pSMBW->ByteCount = cpu_to_le16(count + 5);
2204 }
Steve French3e844692005-10-03 13:37:24 -07002205 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002206 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002207 iov[0].iov_len = smb_hdr_len + 4;
2208 else /* wct == 12 pad bigger by four bytes */
2209 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002210
Steve French3e844692005-10-03 13:37:24 -07002211
Pavel Shilovskyba9ad722012-09-18 16:20:30 -07002212 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002213 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002215 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002216 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002217 /* presumably this can not happen, but best to be safe */
2218 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002219 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002220 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002221 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2222 *nbytes = (*nbytes) << 16;
2223 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302224
2225 /*
2226 * Mask off high 16 bits when bytes written as returned by the
2227 * server is greater than bytes requested by the client. OS/2
2228 * servers are known to set incorrect CountHigh values.
2229 */
2230 if (*nbytes > count)
2231 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Steve French4b8f9302006-02-26 16:41:18 +00002234/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002235 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002236 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002237 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002238 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Steve French50c2f752007-07-13 00:33:32 +00002240 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 since file handle passed in no longer valid */
2242
2243 return rc;
2244}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002245
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002246int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2247 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002248 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2249{
2250 int rc = 0;
2251 LOCK_REQ *pSMB = NULL;
2252 struct kvec iov[2];
2253 int resp_buf_type;
2254 __u16 count;
2255
Joe Perchesf96637b2013-05-04 22:12:25 -05002256 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2257 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002258
2259 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2260 if (rc)
2261 return rc;
2262
2263 pSMB->Timeout = 0;
2264 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2265 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2266 pSMB->LockType = lock_type;
2267 pSMB->AndXCommand = 0xFF; /* none */
2268 pSMB->Fid = netfid; /* netfid stays le */
2269
2270 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2271 inc_rfc1001_len(pSMB, count);
2272 pSMB->ByteCount = cpu_to_le16(count);
2273
2274 iov[0].iov_base = (char *)pSMB;
2275 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2276 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2277 iov[1].iov_base = (char *)buf;
2278 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2279
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002280 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002281 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2282 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002283 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002284
2285 return rc;
2286}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002289CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002290 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002292 const __u32 numLock, const __u8 lockType,
2293 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294{
2295 int rc = 0;
2296 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002297/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002299 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 __u16 count;
2301
Joe Perchesf96637b2013-05-04 22:12:25 -05002302 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2303 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002304 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 if (rc)
2307 return rc;
2308
Steve French790fe572007-07-07 19:25:05 +00002309 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002310 /* no response expected */
2311 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002313 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002314 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2316 } else {
2317 pSMB->Timeout = 0;
2318 }
2319
2320 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2321 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2322 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002323 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 pSMB->AndXCommand = 0xFF; /* none */
2325 pSMB->Fid = smb_file_id; /* netfid stays le */
2326
Steve French790fe572007-07-07 19:25:05 +00002327 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002328 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 /* BB where to store pid high? */
2330 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2331 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2332 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2333 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2334 count = sizeof(LOCKING_ANDX_RANGE);
2335 } else {
2336 /* oplock break */
2337 count = 0;
2338 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002339 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 pSMB->ByteCount = cpu_to_le16(count);
2341
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002342 if (waitFlag) {
2343 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002344 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002345 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002346 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002347 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002348 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002349 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002350 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002351 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002352 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
Steve French50c2f752007-07-13 00:33:32 +00002354 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 since file handle passed in no longer valid */
2356 return rc;
2357}
2358
2359int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002360CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002361 const __u16 smb_file_id, const __u32 netpid,
2362 const loff_t start_offset, const __u64 len,
2363 struct file_lock *pLockData, const __u16 lock_type,
2364 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002365{
2366 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2367 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002368 struct cifs_posix_lock *parm_data;
2369 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002370 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002371 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002372 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002373 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002374 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002375
Joe Perchesf96637b2013-05-04 22:12:25 -05002376 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002377
Steve French08547b02006-02-28 22:39:25 +00002378 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2379
2380 if (rc)
2381 return rc;
2382
2383 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2384
Steve French50c2f752007-07-13 00:33:32 +00002385 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002386 pSMB->MaxSetupCount = 0;
2387 pSMB->Reserved = 0;
2388 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002389 pSMB->Reserved2 = 0;
2390 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2391 offset = param_offset + params;
2392
Steve French08547b02006-02-28 22:39:25 +00002393 count = sizeof(struct cifs_posix_lock);
2394 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002395 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002396 pSMB->SetupCount = 1;
2397 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002398 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002399 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2400 else
2401 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2402 byte_count = 3 /* pad */ + params + count;
2403 pSMB->DataCount = cpu_to_le16(count);
2404 pSMB->ParameterCount = cpu_to_le16(params);
2405 pSMB->TotalDataCount = pSMB->DataCount;
2406 pSMB->TotalParameterCount = pSMB->ParameterCount;
2407 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002408 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002409 (((char *) &pSMB->hdr.Protocol) + offset);
2410
2411 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002412 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002413 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002414 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002415 pSMB->Timeout = cpu_to_le32(-1);
2416 } else
2417 pSMB->Timeout = 0;
2418
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002419 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002420 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002421 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002422
2423 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002424 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002425 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2426 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002427 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002428 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002429 if (waitFlag) {
2430 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2431 (struct smb_hdr *) pSMBr, &bytes_returned);
2432 } else {
Steve French133672e2007-11-13 22:41:37 +00002433 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002434 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002435 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2436 &resp_buf_type, timeout);
2437 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2438 not try to free it twice below on exit */
2439 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002440 }
2441
Steve French08547b02006-02-28 22:39:25 +00002442 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002443 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002444 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002445 /* lock structure can be returned on get */
2446 __u16 data_offset;
2447 __u16 data_count;
2448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002449
Jeff Layton820a8032011-05-04 08:05:26 -04002450 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002451 rc = -EIO; /* bad smb */
2452 goto plk_err_exit;
2453 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002454 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2455 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002456 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002457 rc = -EIO;
2458 goto plk_err_exit;
2459 }
2460 parm_data = (struct cifs_posix_lock *)
2461 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002462 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002463 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002464 else {
2465 if (parm_data->lock_type ==
2466 __constant_cpu_to_le16(CIFS_RDLCK))
2467 pLockData->fl_type = F_RDLCK;
2468 else if (parm_data->lock_type ==
2469 __constant_cpu_to_le16(CIFS_WRLCK))
2470 pLockData->fl_type = F_WRLCK;
2471
Steve French5443d132011-03-13 05:08:25 +00002472 pLockData->fl_start = le64_to_cpu(parm_data->start);
2473 pLockData->fl_end = pLockData->fl_start +
2474 le64_to_cpu(parm_data->length) - 1;
2475 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002476 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002477 }
Steve French50c2f752007-07-13 00:33:32 +00002478
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002479plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002480 if (pSMB)
2481 cifs_small_buf_release(pSMB);
2482
Steve French133672e2007-11-13 22:41:37 +00002483 if (resp_buf_type == CIFS_SMALL_BUFFER)
2484 cifs_small_buf_release(iov[0].iov_base);
2485 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2486 cifs_buf_release(iov[0].iov_base);
2487
Steve French08547b02006-02-28 22:39:25 +00002488 /* Note: On -EAGAIN error only caller can retry on handle based calls
2489 since file handle passed in no longer valid */
2490
2491 return rc;
2492}
2493
2494
2495int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002496CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497{
2498 int rc = 0;
2499 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002500 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
2502/* do not retry on dead session on close */
2503 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002504 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 return 0;
2506 if (rc)
2507 return rc;
2508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002510 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002512 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002513 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002515 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002517 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 }
2519 }
2520
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002522 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 rc = 0;
2524
2525 return rc;
2526}
2527
2528int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002529CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002530{
2531 int rc = 0;
2532 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002533 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002534
2535 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2536 if (rc)
2537 return rc;
2538
2539 pSMB->FileID = (__u16) smb_file_id;
2540 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002541 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002542 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002543 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002544 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002545
2546 return rc;
2547}
2548
2549int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002550CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002551 const char *from_name, const char *to_name,
2552 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553{
2554 int rc = 0;
2555 RENAME_REQ *pSMB = NULL;
2556 RENAME_RSP *pSMBr = NULL;
2557 int bytes_returned;
2558 int name_len, name_len2;
2559 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002560 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561
Joe Perchesf96637b2013-05-04 22:12:25 -05002562 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563renameRetry:
2564 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2565 (void **) &pSMBr);
2566 if (rc)
2567 return rc;
2568
2569 pSMB->BufferFormat = 0x04;
2570 pSMB->SearchAttributes =
2571 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2572 ATTR_DIRECTORY);
2573
2574 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002575 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2576 from_name, PATH_MAX,
2577 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 name_len++; /* trailing null */
2579 name_len *= 2;
2580 pSMB->OldFileName[name_len] = 0x04; /* pad */
2581 /* protocol requires ASCII signature byte on Unicode string */
2582 pSMB->OldFileName[name_len + 1] = 0x00;
2583 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002584 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002585 to_name, PATH_MAX, cifs_sb->local_nls,
2586 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2588 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002589 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002590 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002592 strncpy(pSMB->OldFileName, from_name, name_len);
2593 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 name_len2++; /* trailing null */
2595 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002596 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 name_len2++; /* trailing null */
2598 name_len2++; /* signature byte */
2599 }
2600
2601 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002602 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 pSMB->ByteCount = cpu_to_le16(count);
2604
2605 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2606 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002607 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002608 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002609 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 cifs_buf_release(pSMB);
2612
2613 if (rc == -EAGAIN)
2614 goto renameRetry;
2615
2616 return rc;
2617}
2618
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002619int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002620 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002621 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622{
2623 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2624 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002625 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 char *data_offset;
2627 char dummy_string[30];
2628 int rc = 0;
2629 int bytes_returned = 0;
2630 int len_of_str;
2631 __u16 params, param_offset, offset, count, byte_count;
2632
Joe Perchesf96637b2013-05-04 22:12:25 -05002633 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2635 (void **) &pSMBr);
2636 if (rc)
2637 return rc;
2638
2639 params = 6;
2640 pSMB->MaxSetupCount = 0;
2641 pSMB->Reserved = 0;
2642 pSMB->Flags = 0;
2643 pSMB->Timeout = 0;
2644 pSMB->Reserved2 = 0;
2645 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2646 offset = param_offset + params;
2647
2648 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2649 rename_info = (struct set_file_rename *) data_offset;
2650 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002651 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 pSMB->SetupCount = 1;
2653 pSMB->Reserved3 = 0;
2654 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2655 byte_count = 3 /* pad */ + params;
2656 pSMB->ParameterCount = cpu_to_le16(params);
2657 pSMB->TotalParameterCount = pSMB->ParameterCount;
2658 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2659 pSMB->DataOffset = cpu_to_le16(offset);
2660 /* construct random name ".cifs_tmp<inodenum><mid>" */
2661 rename_info->overwrite = cpu_to_le32(1);
2662 rename_info->root_fid = 0;
2663 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002664 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002665 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002666 len_of_str =
2667 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002668 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002670 len_of_str =
2671 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002672 target_name, PATH_MAX, nls_codepage,
2673 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 }
2675 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002676 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 byte_count += count;
2678 pSMB->DataCount = cpu_to_le16(count);
2679 pSMB->TotalDataCount = pSMB->DataCount;
2680 pSMB->Fid = netfid;
2681 pSMB->InformationLevel =
2682 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2683 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002684 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 pSMB->ByteCount = cpu_to_le16(byte_count);
2686 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002688 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002689 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002690 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2691 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002692
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 cifs_buf_release(pSMB);
2694
2695 /* Note: On -EAGAIN error only caller can retry on handle based calls
2696 since file handle passed in no longer valid */
2697
2698 return rc;
2699}
2700
2701int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002702CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2703 const char *fromName, const __u16 target_tid, const char *toName,
2704 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705{
2706 int rc = 0;
2707 COPY_REQ *pSMB = NULL;
2708 COPY_RSP *pSMBr = NULL;
2709 int bytes_returned;
2710 int name_len, name_len2;
2711 __u16 count;
2712
Joe Perchesf96637b2013-05-04 22:12:25 -05002713 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714copyRetry:
2715 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2716 (void **) &pSMBr);
2717 if (rc)
2718 return rc;
2719
2720 pSMB->BufferFormat = 0x04;
2721 pSMB->Tid2 = target_tid;
2722
2723 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2724
2725 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002726 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2727 fromName, PATH_MAX, nls_codepage,
2728 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 name_len++; /* trailing null */
2730 name_len *= 2;
2731 pSMB->OldFileName[name_len] = 0x04; /* pad */
2732 /* protocol requires ASCII signature byte on Unicode string */
2733 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002734 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002735 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2736 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2738 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002739 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 name_len = strnlen(fromName, PATH_MAX);
2741 name_len++; /* trailing null */
2742 strncpy(pSMB->OldFileName, fromName, name_len);
2743 name_len2 = strnlen(toName, PATH_MAX);
2744 name_len2++; /* trailing null */
2745 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2746 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2747 name_len2++; /* trailing null */
2748 name_len2++; /* signature byte */
2749 }
2750
2751 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002752 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 pSMB->ByteCount = cpu_to_le16(count);
2754
2755 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2756 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2757 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002758 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2759 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 }
Steve French0d817bc2008-05-22 02:02:03 +00002761 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
2763 if (rc == -EAGAIN)
2764 goto copyRetry;
2765
2766 return rc;
2767}
2768
2769int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002770CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 const char *fromName, const char *toName,
2772 const struct nls_table *nls_codepage)
2773{
2774 TRANSACTION2_SPI_REQ *pSMB = NULL;
2775 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2776 char *data_offset;
2777 int name_len;
2778 int name_len_target;
2779 int rc = 0;
2780 int bytes_returned = 0;
2781 __u16 params, param_offset, offset, byte_count;
2782
Joe Perchesf96637b2013-05-04 22:12:25 -05002783 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784createSymLinkRetry:
2785 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2786 (void **) &pSMBr);
2787 if (rc)
2788 return rc;
2789
2790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2791 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002792 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2793 /* find define for this maxpathcomponent */
2794 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 name_len++; /* trailing null */
2796 name_len *= 2;
2797
Steve French50c2f752007-07-13 00:33:32 +00002798 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 name_len = strnlen(fromName, PATH_MAX);
2800 name_len++; /* trailing null */
2801 strncpy(pSMB->FileName, fromName, name_len);
2802 }
2803 params = 6 + name_len;
2804 pSMB->MaxSetupCount = 0;
2805 pSMB->Reserved = 0;
2806 pSMB->Flags = 0;
2807 pSMB->Timeout = 0;
2808 pSMB->Reserved2 = 0;
2809 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002810 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 offset = param_offset + params;
2812
2813 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2814 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2815 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002816 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2817 /* find define for this maxpathcomponent */
2818 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 name_len_target++; /* trailing null */
2820 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002821 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 name_len_target = strnlen(toName, PATH_MAX);
2823 name_len_target++; /* trailing null */
2824 strncpy(data_offset, toName, name_len_target);
2825 }
2826
2827 pSMB->MaxParameterCount = cpu_to_le16(2);
2828 /* BB find exact max on data count below from sess */
2829 pSMB->MaxDataCount = cpu_to_le16(1000);
2830 pSMB->SetupCount = 1;
2831 pSMB->Reserved3 = 0;
2832 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2833 byte_count = 3 /* pad */ + params + name_len_target;
2834 pSMB->DataCount = cpu_to_le16(name_len_target);
2835 pSMB->ParameterCount = cpu_to_le16(params);
2836 pSMB->TotalDataCount = pSMB->DataCount;
2837 pSMB->TotalParameterCount = pSMB->ParameterCount;
2838 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2839 pSMB->DataOffset = cpu_to_le16(offset);
2840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2841 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002842 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 pSMB->ByteCount = cpu_to_le16(byte_count);
2844 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2845 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002846 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002847 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002848 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2849 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Steve French0d817bc2008-05-22 02:02:03 +00002851 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
2853 if (rc == -EAGAIN)
2854 goto createSymLinkRetry;
2855
2856 return rc;
2857}
2858
2859int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002860CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002862 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863{
2864 TRANSACTION2_SPI_REQ *pSMB = NULL;
2865 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2866 char *data_offset;
2867 int name_len;
2868 int name_len_target;
2869 int rc = 0;
2870 int bytes_returned = 0;
2871 __u16 params, param_offset, offset, byte_count;
2872
Joe Perchesf96637b2013-05-04 22:12:25 -05002873 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874createHardLinkRetry:
2875 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2876 (void **) &pSMBr);
2877 if (rc)
2878 return rc;
2879
2880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002881 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2882 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 name_len++; /* trailing null */
2884 name_len *= 2;
2885
Steve French50c2f752007-07-13 00:33:32 +00002886 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 name_len = strnlen(toName, PATH_MAX);
2888 name_len++; /* trailing null */
2889 strncpy(pSMB->FileName, toName, name_len);
2890 }
2891 params = 6 + name_len;
2892 pSMB->MaxSetupCount = 0;
2893 pSMB->Reserved = 0;
2894 pSMB->Flags = 0;
2895 pSMB->Timeout = 0;
2896 pSMB->Reserved2 = 0;
2897 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002898 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 offset = param_offset + params;
2900
2901 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2902 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2903 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002904 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2905 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 name_len_target++; /* trailing null */
2907 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002908 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 name_len_target = strnlen(fromName, PATH_MAX);
2910 name_len_target++; /* trailing null */
2911 strncpy(data_offset, fromName, name_len_target);
2912 }
2913
2914 pSMB->MaxParameterCount = cpu_to_le16(2);
2915 /* BB find exact max on data count below from sess*/
2916 pSMB->MaxDataCount = cpu_to_le16(1000);
2917 pSMB->SetupCount = 1;
2918 pSMB->Reserved3 = 0;
2919 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2920 byte_count = 3 /* pad */ + params + name_len_target;
2921 pSMB->ParameterCount = cpu_to_le16(params);
2922 pSMB->TotalParameterCount = pSMB->ParameterCount;
2923 pSMB->DataCount = cpu_to_le16(name_len_target);
2924 pSMB->TotalDataCount = pSMB->DataCount;
2925 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2926 pSMB->DataOffset = cpu_to_le16(offset);
2927 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2928 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002929 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 pSMB->ByteCount = cpu_to_le16(byte_count);
2931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002933 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002934 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002935 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2936 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
2938 cifs_buf_release(pSMB);
2939 if (rc == -EAGAIN)
2940 goto createHardLinkRetry;
2941
2942 return rc;
2943}
2944
2945int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002946CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002947 const char *from_name, const char *to_name,
2948 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949{
2950 int rc = 0;
2951 NT_RENAME_REQ *pSMB = NULL;
2952 RENAME_RSP *pSMBr = NULL;
2953 int bytes_returned;
2954 int name_len, name_len2;
2955 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002956 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957
Joe Perchesf96637b2013-05-04 22:12:25 -05002958 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959winCreateHardLinkRetry:
2960
2961 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2962 (void **) &pSMBr);
2963 if (rc)
2964 return rc;
2965
2966 pSMB->SearchAttributes =
2967 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2968 ATTR_DIRECTORY);
2969 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2970 pSMB->ClusterCount = 0;
2971
2972 pSMB->BufferFormat = 0x04;
2973
2974 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2975 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002976 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2977 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 name_len++; /* trailing null */
2979 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002980
2981 /* protocol specifies ASCII buffer format (0x04) for unicode */
2982 pSMB->OldFileName[name_len] = 0x04;
2983 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002985 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002986 to_name, PATH_MAX, cifs_sb->local_nls,
2987 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2989 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002990 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002991 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002993 strncpy(pSMB->OldFileName, from_name, name_len);
2994 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 name_len2++; /* trailing null */
2996 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002997 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 name_len2++; /* trailing null */
2999 name_len2++; /* signature byte */
3000 }
3001
3002 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003003 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 pSMB->ByteCount = cpu_to_le16(count);
3005
3006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003008 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003009 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003010 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003011
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 cifs_buf_release(pSMB);
3013 if (rc == -EAGAIN)
3014 goto winCreateHardLinkRetry;
3015
3016 return rc;
3017}
3018
3019int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003020CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003021 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 const struct nls_table *nls_codepage)
3023{
3024/* SMB_QUERY_FILE_UNIX_LINK */
3025 TRANSACTION2_QPI_REQ *pSMB = NULL;
3026 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3027 int rc = 0;
3028 int bytes_returned;
3029 int name_len;
3030 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003031 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032
Joe Perchesf96637b2013-05-04 22:12:25 -05003033 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034
3035querySymLinkRetry:
3036 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3037 (void **) &pSMBr);
3038 if (rc)
3039 return rc;
3040
3041 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3042 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003043 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3044 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 name_len++; /* trailing null */
3046 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003047 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 name_len = strnlen(searchName, PATH_MAX);
3049 name_len++; /* trailing null */
3050 strncpy(pSMB->FileName, searchName, name_len);
3051 }
3052
3053 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3054 pSMB->TotalDataCount = 0;
3055 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003056 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 pSMB->MaxSetupCount = 0;
3058 pSMB->Reserved = 0;
3059 pSMB->Flags = 0;
3060 pSMB->Timeout = 0;
3061 pSMB->Reserved2 = 0;
3062 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003063 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 pSMB->DataCount = 0;
3065 pSMB->DataOffset = 0;
3066 pSMB->SetupCount = 1;
3067 pSMB->Reserved3 = 0;
3068 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3069 byte_count = params + 1 /* pad */ ;
3070 pSMB->TotalParameterCount = cpu_to_le16(params);
3071 pSMB->ParameterCount = pSMB->TotalParameterCount;
3072 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3073 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003074 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 pSMB->ByteCount = cpu_to_le16(byte_count);
3076
3077 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3078 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3079 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003080 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 } else {
3082 /* decode response */
3083
3084 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003086 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003087 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003089 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003090 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Jeff Layton460b9692009-04-30 07:17:56 -04003092 data_start = ((char *) &pSMBr->hdr.Protocol) +
3093 le16_to_cpu(pSMBr->t2.DataOffset);
3094
Steve French0e0d2cf2009-05-01 05:27:32 +00003095 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3096 is_unicode = true;
3097 else
3098 is_unicode = false;
3099
Steve French737b7582005-04-28 22:41:06 -07003100 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003101 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3102 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003103 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003104 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 }
3106 }
3107 cifs_buf_release(pSMB);
3108 if (rc == -EAGAIN)
3109 goto querySymLinkRetry;
3110 return rc;
3111}
3112
Steve Frenchc52a9552011-02-24 06:16:22 +00003113#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3114/*
3115 * Recent Windows versions now create symlinks more frequently
3116 * and they use the "reparse point" mechanism below. We can of course
3117 * do symlinks nicely to Samba and other servers which support the
3118 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3119 * "MF" symlinks optionally, but for recent Windows we really need to
3120 * reenable the code below and fix the cifs_symlink callers to handle this.
3121 * In the interim this code has been moved to its own config option so
3122 * it is not compiled in by default until callers fixed up and more tested.
3123 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003125CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003127 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 const struct nls_table *nls_codepage)
3129{
3130 int rc = 0;
3131 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003132 struct smb_com_transaction_ioctl_req *pSMB;
3133 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
Joe Perchesf96637b2013-05-04 22:12:25 -05003135 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3136 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3138 (void **) &pSMBr);
3139 if (rc)
3140 return rc;
3141
3142 pSMB->TotalParameterCount = 0 ;
3143 pSMB->TotalDataCount = 0;
3144 pSMB->MaxParameterCount = cpu_to_le32(2);
3145 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003146 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 pSMB->MaxSetupCount = 4;
3148 pSMB->Reserved = 0;
3149 pSMB->ParameterOffset = 0;
3150 pSMB->DataCount = 0;
3151 pSMB->DataOffset = 0;
3152 pSMB->SetupCount = 4;
3153 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3154 pSMB->ParameterCount = pSMB->TotalParameterCount;
3155 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3156 pSMB->IsFsctl = 1; /* FSCTL */
3157 pSMB->IsRootFlag = 0;
3158 pSMB->Fid = fid; /* file handle always le */
3159 pSMB->ByteCount = 0;
3160
3161 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3163 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003164 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 } else { /* decode response */
3166 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3167 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003168 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3169 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003171 goto qreparse_out;
3172 }
3173 if (data_count && (data_count < 2048)) {
3174 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003175 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
Steve Frenchafe48c32009-05-02 05:25:46 +00003177 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003178 (struct reparse_data *)
3179 ((char *)&pSMBr->hdr.Protocol
3180 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003181 if ((char *)reparse_buf >= end_of_smb) {
3182 rc = -EIO;
3183 goto qreparse_out;
3184 }
3185 if ((reparse_buf->LinkNamesBuf +
3186 reparse_buf->TargetNameOffset +
3187 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003188 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003189 rc = -EIO;
3190 goto qreparse_out;
3191 }
Steve French50c2f752007-07-13 00:33:32 +00003192
Steve Frenchafe48c32009-05-02 05:25:46 +00003193 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3194 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003195 (reparse_buf->LinkNamesBuf +
3196 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003197 buflen,
3198 reparse_buf->TargetNameLen,
3199 nls_codepage, 0);
3200 } else { /* ASCII names */
3201 strncpy(symlinkinfo,
3202 reparse_buf->LinkNamesBuf +
3203 reparse_buf->TargetNameOffset,
3204 min_t(const int, buflen,
3205 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003207 } else {
3208 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003209 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003211 symlinkinfo[buflen] = 0; /* just in case so the caller
3212 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003213 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 }
Steve French989c7e52009-05-02 05:32:20 +00003215
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003217 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218
3219 /* Note: On -EAGAIN error only caller can retry on handle based calls
3220 since file handle passed in no longer valid */
3221
3222 return rc;
3223}
Steve Frenchc52a9552011-02-24 06:16:22 +00003224#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225
3226#ifdef CONFIG_CIFS_POSIX
3227
3228/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003229static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3230 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231{
3232 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003233 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3234 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3235 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003236/*
3237 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3238 ace->e_perm, ace->e_tag, ace->e_id);
3239*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
3241 return;
3242}
3243
3244/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003245static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3246 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247{
3248 int size = 0;
3249 int i;
3250 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003251 struct cifs_posix_ace *pACE;
3252 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3253 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254
3255 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3256 return -EOPNOTSUPP;
3257
Steve French790fe572007-07-07 19:25:05 +00003258 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 count = le16_to_cpu(cifs_acl->access_entry_count);
3260 pACE = &cifs_acl->ace_array[0];
3261 size = sizeof(struct cifs_posix_acl);
3262 size += sizeof(struct cifs_posix_ace) * count;
3263 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003264 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003265 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3266 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 return -EINVAL;
3268 }
Steve French790fe572007-07-07 19:25:05 +00003269 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 count = le16_to_cpu(cifs_acl->access_entry_count);
3271 size = sizeof(struct cifs_posix_acl);
3272 size += sizeof(struct cifs_posix_ace) * count;
3273/* skip past access ACEs to get to default ACEs */
3274 pACE = &cifs_acl->ace_array[count];
3275 count = le16_to_cpu(cifs_acl->default_entry_count);
3276 size += sizeof(struct cifs_posix_ace) * count;
3277 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003278 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 return -EINVAL;
3280 } else {
3281 /* illegal type */
3282 return -EINVAL;
3283 }
3284
3285 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003286 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003287 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003288 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 return -ERANGE;
3290 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003291 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003292 for (i = 0; i < count ; i++) {
3293 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3294 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 }
3296 }
3297 return size;
3298}
3299
Steve French50c2f752007-07-13 00:33:32 +00003300static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3301 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302{
3303 __u16 rc = 0; /* 0 = ACL converted ok */
3304
Steve Frenchff7feac2005-11-15 16:45:16 -08003305 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3306 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003308 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 /* Probably no need to le convert -1 on any arch but can not hurt */
3310 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003311 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003312 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003313/*
3314 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3315 ace->e_perm, ace->e_tag, ace->e_id);
3316*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 return rc;
3318}
3319
3320/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003321static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3322 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323{
3324 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003325 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3326 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 int count;
3328 int i;
3329
Steve French790fe572007-07-07 19:25:05 +00003330 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 return 0;
3332
3333 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003334 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3335 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003336 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003337 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3338 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 return 0;
3340 }
3341 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003342 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003343 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003344 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003345 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003347 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 return 0;
3349 }
Steve French50c2f752007-07-13 00:33:32 +00003350 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3352 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003353 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 /* ACE not converted */
3355 break;
3356 }
3357 }
Steve French790fe572007-07-07 19:25:05 +00003358 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3360 rc += sizeof(struct cifs_posix_acl);
3361 /* BB add check to make sure ACL does not overflow SMB */
3362 }
3363 return rc;
3364}
3365
3366int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003367CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003368 const unsigned char *searchName,
3369 char *acl_inf, const int buflen, const int acl_type,
3370 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371{
3372/* SMB_QUERY_POSIX_ACL */
3373 TRANSACTION2_QPI_REQ *pSMB = NULL;
3374 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3375 int rc = 0;
3376 int bytes_returned;
3377 int name_len;
3378 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003379
Joe Perchesf96637b2013-05-04 22:12:25 -05003380 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381
3382queryAclRetry:
3383 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3384 (void **) &pSMBr);
3385 if (rc)
3386 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003387
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3389 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003390 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3391 searchName, PATH_MAX, nls_codepage,
3392 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 name_len++; /* trailing null */
3394 name_len *= 2;
3395 pSMB->FileName[name_len] = 0;
3396 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003397 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 name_len = strnlen(searchName, PATH_MAX);
3399 name_len++; /* trailing null */
3400 strncpy(pSMB->FileName, searchName, name_len);
3401 }
3402
3403 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3404 pSMB->TotalDataCount = 0;
3405 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003406 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 pSMB->MaxDataCount = cpu_to_le16(4000);
3408 pSMB->MaxSetupCount = 0;
3409 pSMB->Reserved = 0;
3410 pSMB->Flags = 0;
3411 pSMB->Timeout = 0;
3412 pSMB->Reserved2 = 0;
3413 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003414 offsetof(struct smb_com_transaction2_qpi_req,
3415 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 pSMB->DataCount = 0;
3417 pSMB->DataOffset = 0;
3418 pSMB->SetupCount = 1;
3419 pSMB->Reserved3 = 0;
3420 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3421 byte_count = params + 1 /* pad */ ;
3422 pSMB->TotalParameterCount = cpu_to_le16(params);
3423 pSMB->ParameterCount = pSMB->TotalParameterCount;
3424 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3425 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003426 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 pSMB->ByteCount = cpu_to_le16(byte_count);
3428
3429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003431 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003433 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 } else {
3435 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003436
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003439 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 rc = -EIO; /* bad smb */
3441 else {
3442 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3443 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3444 rc = cifs_copy_posix_acl(acl_inf,
3445 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003446 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 }
3448 }
3449 cifs_buf_release(pSMB);
3450 if (rc == -EAGAIN)
3451 goto queryAclRetry;
3452 return rc;
3453}
3454
3455int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003456CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003457 const unsigned char *fileName,
3458 const char *local_acl, const int buflen,
3459 const int acl_type,
3460 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461{
3462 struct smb_com_transaction2_spi_req *pSMB = NULL;
3463 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3464 char *parm_data;
3465 int name_len;
3466 int rc = 0;
3467 int bytes_returned = 0;
3468 __u16 params, byte_count, data_count, param_offset, offset;
3469
Joe Perchesf96637b2013-05-04 22:12:25 -05003470 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471setAclRetry:
3472 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003473 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 if (rc)
3475 return rc;
3476 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3477 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003478 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3479 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 name_len++; /* trailing null */
3481 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003482 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 name_len = strnlen(fileName, PATH_MAX);
3484 name_len++; /* trailing null */
3485 strncpy(pSMB->FileName, fileName, name_len);
3486 }
3487 params = 6 + name_len;
3488 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003489 /* BB find max SMB size from sess */
3490 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 pSMB->MaxSetupCount = 0;
3492 pSMB->Reserved = 0;
3493 pSMB->Flags = 0;
3494 pSMB->Timeout = 0;
3495 pSMB->Reserved2 = 0;
3496 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003497 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 offset = param_offset + params;
3499 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3500 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3501
3502 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003503 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
Steve French790fe572007-07-07 19:25:05 +00003505 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 rc = -EOPNOTSUPP;
3507 goto setACLerrorExit;
3508 }
3509 pSMB->DataOffset = cpu_to_le16(offset);
3510 pSMB->SetupCount = 1;
3511 pSMB->Reserved3 = 0;
3512 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3513 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3514 byte_count = 3 /* pad */ + params + data_count;
3515 pSMB->DataCount = cpu_to_le16(data_count);
3516 pSMB->TotalDataCount = pSMB->DataCount;
3517 pSMB->ParameterCount = cpu_to_le16(params);
3518 pSMB->TotalParameterCount = pSMB->ParameterCount;
3519 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003520 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 pSMB->ByteCount = cpu_to_le16(byte_count);
3522 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003523 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003524 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003525 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526
3527setACLerrorExit:
3528 cifs_buf_release(pSMB);
3529 if (rc == -EAGAIN)
3530 goto setAclRetry;
3531 return rc;
3532}
3533
Steve Frenchf654bac2005-04-28 22:41:04 -07003534/* BB fix tabs in this function FIXME BB */
3535int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003536CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003537 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003538{
Steve French50c2f752007-07-13 00:33:32 +00003539 int rc = 0;
3540 struct smb_t2_qfi_req *pSMB = NULL;
3541 struct smb_t2_qfi_rsp *pSMBr = NULL;
3542 int bytes_returned;
3543 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003544
Joe Perchesf96637b2013-05-04 22:12:25 -05003545 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003546 if (tcon == NULL)
3547 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003548
3549GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003550 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3551 (void **) &pSMBr);
3552 if (rc)
3553 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003554
Steve Frenchad7a2922008-02-07 23:25:02 +00003555 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003556 pSMB->t2.TotalDataCount = 0;
3557 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3558 /* BB find exact max data count below from sess structure BB */
3559 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3560 pSMB->t2.MaxSetupCount = 0;
3561 pSMB->t2.Reserved = 0;
3562 pSMB->t2.Flags = 0;
3563 pSMB->t2.Timeout = 0;
3564 pSMB->t2.Reserved2 = 0;
3565 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3566 Fid) - 4);
3567 pSMB->t2.DataCount = 0;
3568 pSMB->t2.DataOffset = 0;
3569 pSMB->t2.SetupCount = 1;
3570 pSMB->t2.Reserved3 = 0;
3571 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3572 byte_count = params + 1 /* pad */ ;
3573 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3574 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3575 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3576 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003577 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003578 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003579 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003580
Steve French790fe572007-07-07 19:25:05 +00003581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3582 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3583 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003584 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003585 } else {
3586 /* decode response */
3587 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003588 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003589 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003590 /* If rc should we check for EOPNOSUPP and
3591 disable the srvino flag? or in caller? */
3592 rc = -EIO; /* bad smb */
3593 else {
3594 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3595 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3596 struct file_chattr_info *pfinfo;
3597 /* BB Do we need a cast or hash here ? */
3598 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003599 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003600 rc = -EIO;
3601 goto GetExtAttrOut;
3602 }
3603 pfinfo = (struct file_chattr_info *)
3604 (data_offset + (char *) &pSMBr->hdr.Protocol);
3605 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003606 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003607 }
3608 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003609GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003610 cifs_buf_release(pSMB);
3611 if (rc == -EAGAIN)
3612 goto GetExtAttrRetry;
3613 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003614}
3615
Steve Frenchf654bac2005-04-28 22:41:04 -07003616#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617
Jeff Layton79df1ba2010-12-06 12:52:08 -05003618#ifdef CONFIG_CIFS_ACL
3619/*
3620 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3621 * all NT TRANSACTS that we init here have total parm and data under about 400
3622 * bytes (to fit in small cifs buffer size), which is the case so far, it
3623 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3624 * returned setup area) and MaxParameterCount (returned parms size) must be set
3625 * by caller
3626 */
3627static int
3628smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003629 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003630 void **ret_buf)
3631{
3632 int rc;
3633 __u32 temp_offset;
3634 struct smb_com_ntransact_req *pSMB;
3635
3636 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3637 (void **)&pSMB);
3638 if (rc)
3639 return rc;
3640 *ret_buf = (void *)pSMB;
3641 pSMB->Reserved = 0;
3642 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3643 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003644 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003645 pSMB->ParameterCount = pSMB->TotalParameterCount;
3646 pSMB->DataCount = pSMB->TotalDataCount;
3647 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3648 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3649 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3650 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3651 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3652 pSMB->SubCommand = cpu_to_le16(sub_command);
3653 return 0;
3654}
3655
3656static int
3657validate_ntransact(char *buf, char **ppparm, char **ppdata,
3658 __u32 *pparmlen, __u32 *pdatalen)
3659{
3660 char *end_of_smb;
3661 __u32 data_count, data_offset, parm_count, parm_offset;
3662 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003663 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003664
3665 *pdatalen = 0;
3666 *pparmlen = 0;
3667
3668 if (buf == NULL)
3669 return -EINVAL;
3670
3671 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3672
Jeff Layton820a8032011-05-04 08:05:26 -04003673 bcc = get_bcc(&pSMBr->hdr);
3674 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003675 (char *)&pSMBr->ByteCount;
3676
3677 data_offset = le32_to_cpu(pSMBr->DataOffset);
3678 data_count = le32_to_cpu(pSMBr->DataCount);
3679 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3680 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3681
3682 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3683 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3684
3685 /* should we also check that parm and data areas do not overlap? */
3686 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003687 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003688 return -EINVAL;
3689 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003690 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003691 return -EINVAL;
3692 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003693 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003694 return -EINVAL;
3695 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003696 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3697 *ppdata, data_count, (data_count + *ppdata),
3698 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003699 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003700 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003701 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003702 return -EINVAL;
3703 }
3704 *pdatalen = data_count;
3705 *pparmlen = parm_count;
3706 return 0;
3707}
3708
Steve French0a4b92c2006-01-12 15:44:21 -08003709/* Get Security Descriptor (by handle) from remote server for a file or dir */
3710int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003711CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003712 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003713{
3714 int rc = 0;
3715 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003716 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003717 struct kvec iov[1];
3718
Joe Perchesf96637b2013-05-04 22:12:25 -05003719 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003720
Steve French630f3f0c2007-10-25 21:17:17 +00003721 *pbuflen = 0;
3722 *acl_inf = NULL;
3723
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003724 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003725 8 /* parm len */, tcon, (void **) &pSMB);
3726 if (rc)
3727 return rc;
3728
3729 pSMB->MaxParameterCount = cpu_to_le32(4);
3730 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3731 pSMB->MaxSetupCount = 0;
3732 pSMB->Fid = fid; /* file handle always le */
3733 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3734 CIFS_ACL_DACL);
3735 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003736 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003737 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003738 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003739
Steve Frencha761ac52007-10-18 21:45:27 +00003740 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003741 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003742 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003743 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003744 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003745 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003746 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003747 __u32 parm_len;
3748 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003749 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003750 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003751
3752/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003753 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003754 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003755 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003756 goto qsec_out;
3757 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3758
Joe Perchesf96637b2013-05-04 22:12:25 -05003759 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3760 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003761
3762 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3763 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003764 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003765 goto qsec_out;
3766 }
3767
3768/* BB check that data area is minimum length and as big as acl_len */
3769
Steve Frenchaf6f4612007-10-16 18:40:37 +00003770 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003771 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003772 cifs_dbg(VFS, "acl length %d does not match %d\n",
3773 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003774 if (*pbuflen > acl_len)
3775 *pbuflen = acl_len;
3776 }
Steve French0a4b92c2006-01-12 15:44:21 -08003777
Steve French630f3f0c2007-10-25 21:17:17 +00003778 /* check if buffer is big enough for the acl
3779 header followed by the smallest SID */
3780 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3781 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003782 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003783 rc = -EINVAL;
3784 *pbuflen = 0;
3785 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003786 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003787 if (*acl_inf == NULL) {
3788 *pbuflen = 0;
3789 rc = -ENOMEM;
3790 }
Steve French630f3f0c2007-10-25 21:17:17 +00003791 }
Steve French0a4b92c2006-01-12 15:44:21 -08003792 }
3793qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003794 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003795 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003796 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003797 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003798/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003799 return rc;
3800}
Steve French97837582007-12-31 07:47:21 +00003801
3802int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003803CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003804 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003805{
3806 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3807 int rc = 0;
3808 int bytes_returned = 0;
3809 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003810 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003811
3812setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003813 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003814 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003815 return rc;
Steve French97837582007-12-31 07:47:21 +00003816
3817 pSMB->MaxSetupCount = 0;
3818 pSMB->Reserved = 0;
3819
3820 param_count = 8;
3821 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3822 data_count = acllen;
3823 data_offset = param_offset + param_count;
3824 byte_count = 3 /* pad */ + param_count;
3825
3826 pSMB->DataCount = cpu_to_le32(data_count);
3827 pSMB->TotalDataCount = pSMB->DataCount;
3828 pSMB->MaxParameterCount = cpu_to_le32(4);
3829 pSMB->MaxDataCount = cpu_to_le32(16384);
3830 pSMB->ParameterCount = cpu_to_le32(param_count);
3831 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3832 pSMB->TotalParameterCount = pSMB->ParameterCount;
3833 pSMB->DataOffset = cpu_to_le32(data_offset);
3834 pSMB->SetupCount = 0;
3835 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3836 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3837
3838 pSMB->Fid = fid; /* file handle always le */
3839 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003840 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003841
3842 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003843 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3844 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003845 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003846 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003847 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003848
3849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3850 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3851
Joe Perchesf96637b2013-05-04 22:12:25 -05003852 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3853 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003854 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003855 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003856 cifs_buf_release(pSMB);
3857
3858 if (rc == -EAGAIN)
3859 goto setCifsAclRetry;
3860
3861 return (rc);
3862}
3863
Jeff Layton79df1ba2010-12-06 12:52:08 -05003864#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003865
Steve French6b8edfe2005-08-23 20:26:03 -07003866/* Legacy Query Path Information call for lookup to old servers such
3867 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003868int
3869SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3870 const char *search_name, FILE_ALL_INFO *data,
3871 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003872{
Steve Frenchad7a2922008-02-07 23:25:02 +00003873 QUERY_INFORMATION_REQ *pSMB;
3874 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003875 int rc = 0;
3876 int bytes_returned;
3877 int name_len;
3878
Joe Perchesf96637b2013-05-04 22:12:25 -05003879 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003880QInfRetry:
3881 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003882 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003883 if (rc)
3884 return rc;
3885
3886 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3887 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003888 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003889 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003890 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003891 name_len++; /* trailing null */
3892 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003893 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003894 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003895 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003896 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003897 }
3898 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003899 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003900 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003901 pSMB->ByteCount = cpu_to_le16(name_len);
3902
3903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003905 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003906 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003907 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003908 struct timespec ts;
3909 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003910
3911 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003912 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003913 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003914 ts.tv_nsec = 0;
3915 ts.tv_sec = time;
3916 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003917 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3918 data->LastWriteTime = data->ChangeTime;
3919 data->LastAccessTime = 0;
3920 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003921 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003922 data->EndOfFile = data->AllocationSize;
3923 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003924 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003925 } else
3926 rc = -EIO; /* bad buffer passed in */
3927
3928 cifs_buf_release(pSMB);
3929
3930 if (rc == -EAGAIN)
3931 goto QInfRetry;
3932
3933 return rc;
3934}
3935
Jeff Laytonbcd53572010-02-12 07:44:16 -05003936int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003937CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003938 u16 netfid, FILE_ALL_INFO *pFindData)
3939{
3940 struct smb_t2_qfi_req *pSMB = NULL;
3941 struct smb_t2_qfi_rsp *pSMBr = NULL;
3942 int rc = 0;
3943 int bytes_returned;
3944 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003945
Jeff Laytonbcd53572010-02-12 07:44:16 -05003946QFileInfoRetry:
3947 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3948 (void **) &pSMBr);
3949 if (rc)
3950 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003951
Jeff Laytonbcd53572010-02-12 07:44:16 -05003952 params = 2 /* level */ + 2 /* fid */;
3953 pSMB->t2.TotalDataCount = 0;
3954 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3955 /* BB find exact max data count below from sess structure BB */
3956 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3957 pSMB->t2.MaxSetupCount = 0;
3958 pSMB->t2.Reserved = 0;
3959 pSMB->t2.Flags = 0;
3960 pSMB->t2.Timeout = 0;
3961 pSMB->t2.Reserved2 = 0;
3962 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3963 Fid) - 4);
3964 pSMB->t2.DataCount = 0;
3965 pSMB->t2.DataOffset = 0;
3966 pSMB->t2.SetupCount = 1;
3967 pSMB->t2.Reserved3 = 0;
3968 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3969 byte_count = params + 1 /* pad */ ;
3970 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3971 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3972 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3973 pSMB->Pad = 0;
3974 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003975 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003976
3977 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3978 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3979 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003980 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003981 } else { /* decode response */
3982 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3983
3984 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3985 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003986 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003987 rc = -EIO; /* bad smb */
3988 else if (pFindData) {
3989 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3990 memcpy((char *) pFindData,
3991 (char *) &pSMBr->hdr.Protocol +
3992 data_offset, sizeof(FILE_ALL_INFO));
3993 } else
3994 rc = -ENOMEM;
3995 }
3996 cifs_buf_release(pSMB);
3997 if (rc == -EAGAIN)
3998 goto QFileInfoRetry;
3999
4000 return rc;
4001}
Steve French6b8edfe2005-08-23 20:26:03 -07004002
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004004CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004005 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004006 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004007 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004009 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 TRANSACTION2_QPI_REQ *pSMB = NULL;
4011 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4012 int rc = 0;
4013 int bytes_returned;
4014 int name_len;
4015 __u16 params, byte_count;
4016
Joe Perchesf96637b2013-05-04 22:12:25 -05004017 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018QPathInfoRetry:
4019 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4020 (void **) &pSMBr);
4021 if (rc)
4022 return rc;
4023
4024 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4025 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004026 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004027 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 name_len++; /* trailing null */
4029 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004030 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004031 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004033 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 }
4035
Steve French50c2f752007-07-13 00:33:32 +00004036 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 pSMB->TotalDataCount = 0;
4038 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004039 /* BB find exact max SMB PDU from sess structure BB */
4040 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 pSMB->MaxSetupCount = 0;
4042 pSMB->Reserved = 0;
4043 pSMB->Flags = 0;
4044 pSMB->Timeout = 0;
4045 pSMB->Reserved2 = 0;
4046 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004047 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 pSMB->DataCount = 0;
4049 pSMB->DataOffset = 0;
4050 pSMB->SetupCount = 1;
4051 pSMB->Reserved3 = 0;
4052 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4053 byte_count = params + 1 /* pad */ ;
4054 pSMB->TotalParameterCount = cpu_to_le16(params);
4055 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004056 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004057 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4058 else
4059 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004061 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 pSMB->ByteCount = cpu_to_le16(byte_count);
4063
4064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4066 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004067 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 } else { /* decode response */
4069 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4070
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004071 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4072 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004073 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004075 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004076 rc = -EIO; /* 24 or 26 expected but we do not read
4077 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004078 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004079 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004081
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004082 /*
4083 * On legacy responses we do not read the last field,
4084 * EAsize, fortunately since it varies by subdialect and
4085 * also note it differs on Set vs Get, ie two bytes or 4
4086 * bytes depending but we don't care here.
4087 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004088 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004089 size = sizeof(FILE_INFO_STANDARD);
4090 else
4091 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004092 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004093 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 } else
4095 rc = -ENOMEM;
4096 }
4097 cifs_buf_release(pSMB);
4098 if (rc == -EAGAIN)
4099 goto QPathInfoRetry;
4100
4101 return rc;
4102}
4103
4104int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004105CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004106 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4107{
4108 struct smb_t2_qfi_req *pSMB = NULL;
4109 struct smb_t2_qfi_rsp *pSMBr = NULL;
4110 int rc = 0;
4111 int bytes_returned;
4112 __u16 params, byte_count;
4113
4114UnixQFileInfoRetry:
4115 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4116 (void **) &pSMBr);
4117 if (rc)
4118 return rc;
4119
4120 params = 2 /* level */ + 2 /* fid */;
4121 pSMB->t2.TotalDataCount = 0;
4122 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4123 /* BB find exact max data count below from sess structure BB */
4124 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4125 pSMB->t2.MaxSetupCount = 0;
4126 pSMB->t2.Reserved = 0;
4127 pSMB->t2.Flags = 0;
4128 pSMB->t2.Timeout = 0;
4129 pSMB->t2.Reserved2 = 0;
4130 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4131 Fid) - 4);
4132 pSMB->t2.DataCount = 0;
4133 pSMB->t2.DataOffset = 0;
4134 pSMB->t2.SetupCount = 1;
4135 pSMB->t2.Reserved3 = 0;
4136 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4137 byte_count = params + 1 /* pad */ ;
4138 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4139 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4140 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4141 pSMB->Pad = 0;
4142 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004143 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004144
4145 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4146 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4147 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004148 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004149 } else { /* decode response */
4150 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4151
Jeff Layton820a8032011-05-04 08:05:26 -04004152 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004153 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 -05004154 rc = -EIO; /* bad smb */
4155 } else {
4156 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4157 memcpy((char *) pFindData,
4158 (char *) &pSMBr->hdr.Protocol +
4159 data_offset,
4160 sizeof(FILE_UNIX_BASIC_INFO));
4161 }
4162 }
4163
4164 cifs_buf_release(pSMB);
4165 if (rc == -EAGAIN)
4166 goto UnixQFileInfoRetry;
4167
4168 return rc;
4169}
4170
4171int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004172CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004174 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004175 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176{
4177/* SMB_QUERY_FILE_UNIX_BASIC */
4178 TRANSACTION2_QPI_REQ *pSMB = NULL;
4179 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4180 int rc = 0;
4181 int bytes_returned = 0;
4182 int name_len;
4183 __u16 params, byte_count;
4184
Joe Perchesf96637b2013-05-04 22:12:25 -05004185 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186UnixQPathInfoRetry:
4187 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4188 (void **) &pSMBr);
4189 if (rc)
4190 return rc;
4191
4192 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4193 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004194 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4195 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 name_len++; /* trailing null */
4197 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004198 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 name_len = strnlen(searchName, PATH_MAX);
4200 name_len++; /* trailing null */
4201 strncpy(pSMB->FileName, searchName, name_len);
4202 }
4203
Steve French50c2f752007-07-13 00:33:32 +00004204 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 pSMB->TotalDataCount = 0;
4206 pSMB->MaxParameterCount = cpu_to_le16(2);
4207 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004208 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 pSMB->MaxSetupCount = 0;
4210 pSMB->Reserved = 0;
4211 pSMB->Flags = 0;
4212 pSMB->Timeout = 0;
4213 pSMB->Reserved2 = 0;
4214 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004215 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 pSMB->DataCount = 0;
4217 pSMB->DataOffset = 0;
4218 pSMB->SetupCount = 1;
4219 pSMB->Reserved3 = 0;
4220 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4221 byte_count = params + 1 /* pad */ ;
4222 pSMB->TotalParameterCount = cpu_to_le16(params);
4223 pSMB->ParameterCount = pSMB->TotalParameterCount;
4224 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4225 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004226 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 pSMB->ByteCount = cpu_to_le16(byte_count);
4228
4229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4231 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004232 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 } else { /* decode response */
4234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4235
Jeff Layton820a8032011-05-04 08:05:26 -04004236 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004237 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 -07004238 rc = -EIO; /* bad smb */
4239 } else {
4240 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4241 memcpy((char *) pFindData,
4242 (char *) &pSMBr->hdr.Protocol +
4243 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004244 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 }
4246 }
4247 cifs_buf_release(pSMB);
4248 if (rc == -EAGAIN)
4249 goto UnixQPathInfoRetry;
4250
4251 return rc;
4252}
4253
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254/* xid, tcon, searchName and codepage are input parms, rest are returned */
4255int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004256CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004257 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004258 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004259 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260{
4261/* level 257 SMB_ */
4262 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4263 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004264 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 int rc = 0;
4266 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004267 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004269 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270
Joe Perchesf96637b2013-05-04 22:12:25 -05004271 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
4273findFirstRetry:
4274 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4275 (void **) &pSMBr);
4276 if (rc)
4277 return rc;
4278
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004279 nls_codepage = cifs_sb->local_nls;
4280 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4281
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4283 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004284 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4285 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004286 /* We can not add the asterik earlier in case
4287 it got remapped to 0xF03A as if it were part of the
4288 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004290 if (msearch) {
4291 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4292 pSMB->FileName[name_len+1] = 0;
4293 pSMB->FileName[name_len+2] = '*';
4294 pSMB->FileName[name_len+3] = 0;
4295 name_len += 4; /* now the trailing null */
4296 /* null terminate just in case */
4297 pSMB->FileName[name_len] = 0;
4298 pSMB->FileName[name_len+1] = 0;
4299 name_len += 2;
4300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 } else { /* BB add check for overrun of SMB buf BB */
4302 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004304 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 free buffer exit; BB */
4306 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004307 if (msearch) {
4308 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4309 pSMB->FileName[name_len+1] = '*';
4310 pSMB->FileName[name_len+2] = 0;
4311 name_len += 3;
4312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 }
4314
4315 params = 12 + name_len /* includes null */ ;
4316 pSMB->TotalDataCount = 0; /* no EAs */
4317 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004318 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 pSMB->MaxSetupCount = 0;
4320 pSMB->Reserved = 0;
4321 pSMB->Flags = 0;
4322 pSMB->Timeout = 0;
4323 pSMB->Reserved2 = 0;
4324 byte_count = params + 1 /* pad */ ;
4325 pSMB->TotalParameterCount = cpu_to_le16(params);
4326 pSMB->ParameterCount = pSMB->TotalParameterCount;
4327 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004328 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4329 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 pSMB->DataCount = 0;
4331 pSMB->DataOffset = 0;
4332 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4333 pSMB->Reserved3 = 0;
4334 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4335 pSMB->SearchAttributes =
4336 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4337 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004338 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004339 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4341
4342 /* BB what should we set StorageType to? Does it matter? BB */
4343 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004344 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 pSMB->ByteCount = cpu_to_le16(byte_count);
4346
4347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004349 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350
Steve French88274812006-03-09 22:21:45 +00004351 if (rc) {/* BB add logic to retry regular search if Unix search
4352 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004354 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004355
Steve French88274812006-03-09 22:21:45 +00004356 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357
4358 /* BB eventually could optimize out free and realloc of buf */
4359 /* for this case */
4360 if (rc == -EAGAIN)
4361 goto findFirstRetry;
4362 } else { /* decode response */
4363 /* BB remember to free buffer if error BB */
4364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004365 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004366 unsigned int lnoff;
4367
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004369 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 else
Steve French4b18f2a2008-04-29 00:06:05 +00004371 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
4373 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004374 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004375 psrch_inf->srch_entries_start =
4376 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4379 le16_to_cpu(pSMBr->t2.ParameterOffset));
4380
Steve French790fe572007-07-07 19:25:05 +00004381 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004382 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 else
Steve French4b18f2a2008-04-29 00:06:05 +00004384 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
Steve French50c2f752007-07-13 00:33:32 +00004386 psrch_inf->entries_in_buffer =
4387 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004388 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004390 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004391 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004392 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004393 psrch_inf->last_entry = NULL;
4394 return rc;
4395 }
4396
Steve French0752f152008-10-07 20:03:33 +00004397 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004398 lnoff;
4399
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004400 if (pnetfid)
4401 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 } else {
4403 cifs_buf_release(pSMB);
4404 }
4405 }
4406
4407 return rc;
4408}
4409
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004410int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4411 __u16 searchHandle, __u16 search_flags,
4412 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413{
4414 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4415 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004416 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 char *response_data;
4418 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004419 int bytes_returned;
4420 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 __u16 params, byte_count;
4422
Joe Perchesf96637b2013-05-04 22:12:25 -05004423 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
Steve French4b18f2a2008-04-29 00:06:05 +00004425 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 return -ENOENT;
4427
4428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429 (void **) &pSMBr);
4430 if (rc)
4431 return rc;
4432
Steve French50c2f752007-07-13 00:33:32 +00004433 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 byte_count = 0;
4435 pSMB->TotalDataCount = 0; /* no EAs */
4436 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004437 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 pSMB->MaxSetupCount = 0;
4439 pSMB->Reserved = 0;
4440 pSMB->Flags = 0;
4441 pSMB->Timeout = 0;
4442 pSMB->Reserved2 = 0;
4443 pSMB->ParameterOffset = cpu_to_le16(
4444 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4445 pSMB->DataCount = 0;
4446 pSMB->DataOffset = 0;
4447 pSMB->SetupCount = 1;
4448 pSMB->Reserved3 = 0;
4449 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4450 pSMB->SearchHandle = searchHandle; /* always kept as le */
4451 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004452 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4454 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004455 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456
4457 name_len = psrch_inf->resume_name_len;
4458 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004459 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4461 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004462 /* 14 byte parm len above enough for 2 byte null terminator */
4463 pSMB->ResumeFileName[name_len] = 0;
4464 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 } else {
4466 rc = -EINVAL;
4467 goto FNext2_err_exit;
4468 }
4469 byte_count = params + 1 /* pad */ ;
4470 pSMB->TotalParameterCount = cpu_to_le16(params);
4471 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004472 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004474
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4476 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004477 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 if (rc) {
4479 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004480 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004481 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004482 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004484 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 } else { /* decode response */
4486 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004487
Steve French790fe572007-07-07 19:25:05 +00004488 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004489 unsigned int lnoff;
4490
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 /* BB fixme add lock for file (srch_info) struct here */
4492 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004493 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 else
Steve French4b18f2a2008-04-29 00:06:05 +00004495 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 response_data = (char *) &pSMBr->hdr.Protocol +
4497 le16_to_cpu(pSMBr->t2.ParameterOffset);
4498 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4499 response_data = (char *)&pSMBr->hdr.Protocol +
4500 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004501 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004502 cifs_small_buf_release(
4503 psrch_inf->ntwrk_buf_start);
4504 else
4505 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 psrch_inf->srch_entries_start = response_data;
4507 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004508 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004509 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004510 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 else
Steve French4b18f2a2008-04-29 00:06:05 +00004512 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004513 psrch_inf->entries_in_buffer =
4514 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 psrch_inf->index_of_last_entry +=
4516 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004517 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004518 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004519 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004520 psrch_inf->last_entry = NULL;
4521 return rc;
4522 } else
4523 psrch_inf->last_entry =
4524 psrch_inf->srch_entries_start + lnoff;
4525
Joe Perchesf96637b2013-05-04 22:12:25 -05004526/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4527 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
4529 /* BB fixme add unlock here */
4530 }
4531
4532 }
4533
4534 /* BB On error, should we leave previous search buf (and count and
4535 last entry fields) intact or free the previous one? */
4536
4537 /* Note: On -EAGAIN error only caller can retry on handle based calls
4538 since file handle passed in no longer valid */
4539FNext2_err_exit:
4540 if (rc != 0)
4541 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 return rc;
4543}
4544
4545int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004546CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004547 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548{
4549 int rc = 0;
4550 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
Joe Perchesf96637b2013-05-04 22:12:25 -05004552 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4554
4555 /* no sense returning error if session restarted
4556 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004557 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 return 0;
4559 if (rc)
4560 return rc;
4561
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 pSMB->FileID = searchHandle;
4563 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004564 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004565 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004566 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004567
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004568 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569
4570 /* Since session is dead, search handle closed on server already */
4571 if (rc == -EAGAIN)
4572 rc = 0;
4573
4574 return rc;
4575}
4576
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004578CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004579 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004580 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581{
4582 int rc = 0;
4583 TRANSACTION2_QPI_REQ *pSMB = NULL;
4584 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4585 int name_len, bytes_returned;
4586 __u16 params, byte_count;
4587
Joe Perchesf96637b2013-05-04 22:12:25 -05004588 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004589 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004590 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
4592GetInodeNumberRetry:
4593 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004594 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 if (rc)
4596 return rc;
4597
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4599 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004600 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004601 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004602 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 name_len++; /* trailing null */
4604 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004605 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004606 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004608 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 }
4610
4611 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4612 pSMB->TotalDataCount = 0;
4613 pSMB->MaxParameterCount = cpu_to_le16(2);
4614 /* BB find exact max data count below from sess structure BB */
4615 pSMB->MaxDataCount = cpu_to_le16(4000);
4616 pSMB->MaxSetupCount = 0;
4617 pSMB->Reserved = 0;
4618 pSMB->Flags = 0;
4619 pSMB->Timeout = 0;
4620 pSMB->Reserved2 = 0;
4621 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004622 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 pSMB->DataCount = 0;
4624 pSMB->DataOffset = 0;
4625 pSMB->SetupCount = 1;
4626 pSMB->Reserved3 = 0;
4627 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4628 byte_count = params + 1 /* pad */ ;
4629 pSMB->TotalParameterCount = cpu_to_le16(params);
4630 pSMB->ParameterCount = pSMB->TotalParameterCount;
4631 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4632 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004633 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 pSMB->ByteCount = cpu_to_le16(byte_count);
4635
4636 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4637 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4638 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004639 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 } else {
4641 /* decode response */
4642 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004644 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 /* If rc should we check for EOPNOSUPP and
4646 disable the srvino flag? or in caller? */
4647 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004648 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4650 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004651 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004653 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004654 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 rc = -EIO;
4656 goto GetInodeNumOut;
4657 }
4658 pfinfo = (struct file_internal_info *)
4659 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004660 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 }
4662 }
4663GetInodeNumOut:
4664 cifs_buf_release(pSMB);
4665 if (rc == -EAGAIN)
4666 goto GetInodeNumberRetry;
4667 return rc;
4668}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
Igor Mammedovfec45852008-05-16 13:06:30 +04004670/* parses DFS refferal V3 structure
4671 * caller is responsible for freeing target_nodes
4672 * returns:
4673 * on success - 0
4674 * on failure - errno
4675 */
4676static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004677parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004678 unsigned int *num_of_nodes,
4679 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004680 const struct nls_table *nls_codepage, int remap,
4681 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004682{
4683 int i, rc = 0;
4684 char *data_end;
4685 bool is_unicode;
4686 struct dfs_referral_level_3 *ref;
4687
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004688 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4689 is_unicode = true;
4690 else
4691 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004692 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4693
4694 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004695 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4696 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004697 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004698 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004699 }
4700
4701 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004702 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004703 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4704 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004705 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004706 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004707 }
4708
4709 /* get the upper boundary of the resp buffer */
4710 data_end = (char *)(&(pSMBr->PathConsumed)) +
4711 le16_to_cpu(pSMBr->t2.DataCount);
4712
Joe Perchesf96637b2013-05-04 22:12:25 -05004713 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4714 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004715
Joe Perchesf96637b2013-05-04 22:12:25 -05004716 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4717 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004718 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004719 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004720 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004721 }
4722
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004723 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004724 for (i = 0; i < *num_of_nodes; i++) {
4725 char *temp;
4726 int max_len;
4727 struct dfs_info3_param *node = (*target_nodes)+i;
4728
Steve French0e0d2cf2009-05-01 05:27:32 +00004729 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004730 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004731 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4732 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004733 if (tmp == NULL) {
4734 rc = -ENOMEM;
4735 goto parse_DFS_referrals_exit;
4736 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004737 cifsConvertToUTF16((__le16 *) tmp, searchName,
4738 PATH_MAX, nls_codepage, remap);
4739 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004740 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004741 nls_codepage);
4742 kfree(tmp);
4743 } else
4744 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4745
Igor Mammedovfec45852008-05-16 13:06:30 +04004746 node->server_type = le16_to_cpu(ref->ServerType);
4747 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4748
4749 /* copy DfsPath */
4750 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4751 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004752 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4753 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004754 if (!node->path_name) {
4755 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004756 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004757 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004758
4759 /* copy link target UNC */
4760 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4761 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004762 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4763 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004764 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004765 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004766 goto parse_DFS_referrals_exit;
4767 }
4768
4769 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004770 }
4771
Steve Frencha1fe78f2008-05-16 18:48:38 +00004772parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004773 if (rc) {
4774 free_dfs_info_array(*target_nodes, *num_of_nodes);
4775 *target_nodes = NULL;
4776 *num_of_nodes = 0;
4777 }
4778 return rc;
4779}
4780
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004782CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004783 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004784 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004785 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786{
4787/* TRANS2_GET_DFS_REFERRAL */
4788 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4789 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 int rc = 0;
4791 int bytes_returned;
4792 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004794 *num_of_nodes = 0;
4795 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796
Joe Perchesf96637b2013-05-04 22:12:25 -05004797 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 if (ses == NULL)
4799 return -ENODEV;
4800getDFSRetry:
4801 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4802 (void **) &pSMBr);
4803 if (rc)
4804 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004805
4806 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004807 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004808 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 pSMB->hdr.Tid = ses->ipc_tid;
4810 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004811 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004813 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815
4816 if (ses->capabilities & CAP_UNICODE) {
4817 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4818 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004819 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004820 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004821 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 name_len++; /* trailing null */
4823 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004824 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004825 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004827 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 }
4829
Steve French790fe572007-07-07 19:25:05 +00004830 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004831 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004832 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4833 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4834 }
4835
Steve French50c2f752007-07-13 00:33:32 +00004836 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004837
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 params = 2 /* level */ + name_len /*includes null */ ;
4839 pSMB->TotalDataCount = 0;
4840 pSMB->DataCount = 0;
4841 pSMB->DataOffset = 0;
4842 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004843 /* BB find exact max SMB PDU from sess structure BB */
4844 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 pSMB->MaxSetupCount = 0;
4846 pSMB->Reserved = 0;
4847 pSMB->Flags = 0;
4848 pSMB->Timeout = 0;
4849 pSMB->Reserved2 = 0;
4850 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004851 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 pSMB->SetupCount = 1;
4853 pSMB->Reserved3 = 0;
4854 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4855 byte_count = params + 3 /* pad */ ;
4856 pSMB->ParameterCount = cpu_to_le16(params);
4857 pSMB->TotalParameterCount = pSMB->ParameterCount;
4858 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004859 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 pSMB->ByteCount = cpu_to_le16(byte_count);
4861
4862 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4864 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004865 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004866 goto GetDFSRefExit;
4867 }
4868 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004870 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004871 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004872 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004873 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004875
Joe Perchesf96637b2013-05-04 22:12:25 -05004876 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4877 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004878
4879 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004880 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004881 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004882 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004883
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004885 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886
4887 if (rc == -EAGAIN)
4888 goto getDFSRetry;
4889
4890 return rc;
4891}
4892
Steve French20962432005-09-21 22:05:57 -07004893/* Query File System Info such as free space to old servers such as Win 9x */
4894int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004895SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4896 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004897{
4898/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4899 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4900 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4901 FILE_SYSTEM_ALLOC_INFO *response_data;
4902 int rc = 0;
4903 int bytes_returned = 0;
4904 __u16 params, byte_count;
4905
Joe Perchesf96637b2013-05-04 22:12:25 -05004906 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004907oldQFSInfoRetry:
4908 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4909 (void **) &pSMBr);
4910 if (rc)
4911 return rc;
Steve French20962432005-09-21 22:05:57 -07004912
4913 params = 2; /* level */
4914 pSMB->TotalDataCount = 0;
4915 pSMB->MaxParameterCount = cpu_to_le16(2);
4916 pSMB->MaxDataCount = cpu_to_le16(1000);
4917 pSMB->MaxSetupCount = 0;
4918 pSMB->Reserved = 0;
4919 pSMB->Flags = 0;
4920 pSMB->Timeout = 0;
4921 pSMB->Reserved2 = 0;
4922 byte_count = params + 1 /* pad */ ;
4923 pSMB->TotalParameterCount = cpu_to_le16(params);
4924 pSMB->ParameterCount = pSMB->TotalParameterCount;
4925 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4926 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4927 pSMB->DataCount = 0;
4928 pSMB->DataOffset = 0;
4929 pSMB->SetupCount = 1;
4930 pSMB->Reserved3 = 0;
4931 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4932 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004933 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004934 pSMB->ByteCount = cpu_to_le16(byte_count);
4935
4936 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4937 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4938 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004939 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004940 } else { /* decode response */
4941 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4942
Jeff Layton820a8032011-05-04 08:05:26 -04004943 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004944 rc = -EIO; /* bad smb */
4945 else {
4946 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004947 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004948 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004949
Steve French50c2f752007-07-13 00:33:32 +00004950 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004951 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4952 FSData->f_bsize =
4953 le16_to_cpu(response_data->BytesPerSector) *
4954 le32_to_cpu(response_data->
4955 SectorsPerAllocationUnit);
4956 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004957 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004958 FSData->f_bfree = FSData->f_bavail =
4959 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004960 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4961 (unsigned long long)FSData->f_blocks,
4962 (unsigned long long)FSData->f_bfree,
4963 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004964 }
4965 }
4966 cifs_buf_release(pSMB);
4967
4968 if (rc == -EAGAIN)
4969 goto oldQFSInfoRetry;
4970
4971 return rc;
4972}
4973
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004975CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4976 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977{
4978/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4979 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4980 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4981 FILE_SYSTEM_INFO *response_data;
4982 int rc = 0;
4983 int bytes_returned = 0;
4984 __u16 params, byte_count;
4985
Joe Perchesf96637b2013-05-04 22:12:25 -05004986 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987QFSInfoRetry:
4988 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4989 (void **) &pSMBr);
4990 if (rc)
4991 return rc;
4992
4993 params = 2; /* level */
4994 pSMB->TotalDataCount = 0;
4995 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004996 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 pSMB->MaxSetupCount = 0;
4998 pSMB->Reserved = 0;
4999 pSMB->Flags = 0;
5000 pSMB->Timeout = 0;
5001 pSMB->Reserved2 = 0;
5002 byte_count = params + 1 /* pad */ ;
5003 pSMB->TotalParameterCount = cpu_to_le16(params);
5004 pSMB->ParameterCount = pSMB->TotalParameterCount;
5005 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005006 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 pSMB->DataCount = 0;
5008 pSMB->DataOffset = 0;
5009 pSMB->SetupCount = 1;
5010 pSMB->Reserved3 = 0;
5011 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5012 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005013 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 pSMB->ByteCount = cpu_to_le16(byte_count);
5015
5016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5018 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005019 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005021 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022
Jeff Layton820a8032011-05-04 08:05:26 -04005023 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 rc = -EIO; /* bad smb */
5025 else {
5026 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027
5028 response_data =
5029 (FILE_SYSTEM_INFO
5030 *) (((char *) &pSMBr->hdr.Protocol) +
5031 data_offset);
5032 FSData->f_bsize =
5033 le32_to_cpu(response_data->BytesPerSector) *
5034 le32_to_cpu(response_data->
5035 SectorsPerAllocationUnit);
5036 FSData->f_blocks =
5037 le64_to_cpu(response_data->TotalAllocationUnits);
5038 FSData->f_bfree = FSData->f_bavail =
5039 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005040 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5041 (unsigned long long)FSData->f_blocks,
5042 (unsigned long long)FSData->f_bfree,
5043 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 }
5045 }
5046 cifs_buf_release(pSMB);
5047
5048 if (rc == -EAGAIN)
5049 goto QFSInfoRetry;
5050
5051 return rc;
5052}
5053
5054int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005055CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056{
5057/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5058 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5059 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5060 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5061 int rc = 0;
5062 int bytes_returned = 0;
5063 __u16 params, byte_count;
5064
Joe Perchesf96637b2013-05-04 22:12:25 -05005065 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066QFSAttributeRetry:
5067 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5068 (void **) &pSMBr);
5069 if (rc)
5070 return rc;
5071
5072 params = 2; /* level */
5073 pSMB->TotalDataCount = 0;
5074 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005075 /* BB find exact max SMB PDU from sess structure BB */
5076 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 pSMB->MaxSetupCount = 0;
5078 pSMB->Reserved = 0;
5079 pSMB->Flags = 0;
5080 pSMB->Timeout = 0;
5081 pSMB->Reserved2 = 0;
5082 byte_count = params + 1 /* pad */ ;
5083 pSMB->TotalParameterCount = cpu_to_le16(params);
5084 pSMB->ParameterCount = pSMB->TotalParameterCount;
5085 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005086 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 pSMB->DataCount = 0;
5088 pSMB->DataOffset = 0;
5089 pSMB->SetupCount = 1;
5090 pSMB->Reserved3 = 0;
5091 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5092 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005093 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 pSMB->ByteCount = cpu_to_le16(byte_count);
5095
5096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5098 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005099 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 } else { /* decode response */
5101 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5102
Jeff Layton820a8032011-05-04 08:05:26 -04005103 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005104 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 rc = -EIO; /* bad smb */
5106 } else {
5107 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5108 response_data =
5109 (FILE_SYSTEM_ATTRIBUTE_INFO
5110 *) (((char *) &pSMBr->hdr.Protocol) +
5111 data_offset);
5112 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005113 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 }
5115 }
5116 cifs_buf_release(pSMB);
5117
5118 if (rc == -EAGAIN)
5119 goto QFSAttributeRetry;
5120
5121 return rc;
5122}
5123
5124int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005125CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126{
5127/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5128 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5129 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5130 FILE_SYSTEM_DEVICE_INFO *response_data;
5131 int rc = 0;
5132 int bytes_returned = 0;
5133 __u16 params, byte_count;
5134
Joe Perchesf96637b2013-05-04 22:12:25 -05005135 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136QFSDeviceRetry:
5137 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5138 (void **) &pSMBr);
5139 if (rc)
5140 return rc;
5141
5142 params = 2; /* level */
5143 pSMB->TotalDataCount = 0;
5144 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005145 /* BB find exact max SMB PDU from sess structure BB */
5146 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 pSMB->MaxSetupCount = 0;
5148 pSMB->Reserved = 0;
5149 pSMB->Flags = 0;
5150 pSMB->Timeout = 0;
5151 pSMB->Reserved2 = 0;
5152 byte_count = params + 1 /* pad */ ;
5153 pSMB->TotalParameterCount = cpu_to_le16(params);
5154 pSMB->ParameterCount = pSMB->TotalParameterCount;
5155 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005156 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157
5158 pSMB->DataCount = 0;
5159 pSMB->DataOffset = 0;
5160 pSMB->SetupCount = 1;
5161 pSMB->Reserved3 = 0;
5162 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5163 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005164 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 pSMB->ByteCount = cpu_to_le16(byte_count);
5166
5167 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5168 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5169 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005170 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 } else { /* decode response */
5172 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5173
Jeff Layton820a8032011-05-04 08:05:26 -04005174 if (rc || get_bcc(&pSMBr->hdr) <
5175 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 rc = -EIO; /* bad smb */
5177 else {
5178 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5179 response_data =
Steve French737b7582005-04-28 22:41:06 -07005180 (FILE_SYSTEM_DEVICE_INFO *)
5181 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 data_offset);
5183 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005184 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 }
5186 }
5187 cifs_buf_release(pSMB);
5188
5189 if (rc == -EAGAIN)
5190 goto QFSDeviceRetry;
5191
5192 return rc;
5193}
5194
5195int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005196CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197{
5198/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5199 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5200 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5201 FILE_SYSTEM_UNIX_INFO *response_data;
5202 int rc = 0;
5203 int bytes_returned = 0;
5204 __u16 params, byte_count;
5205
Joe Perchesf96637b2013-05-04 22:12:25 -05005206 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005208 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5209 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 if (rc)
5211 return rc;
5212
5213 params = 2; /* level */
5214 pSMB->TotalDataCount = 0;
5215 pSMB->DataCount = 0;
5216 pSMB->DataOffset = 0;
5217 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005218 /* BB find exact max SMB PDU from sess structure BB */
5219 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 pSMB->MaxSetupCount = 0;
5221 pSMB->Reserved = 0;
5222 pSMB->Flags = 0;
5223 pSMB->Timeout = 0;
5224 pSMB->Reserved2 = 0;
5225 byte_count = params + 1 /* pad */ ;
5226 pSMB->ParameterCount = cpu_to_le16(params);
5227 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005228 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5229 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 pSMB->SetupCount = 1;
5231 pSMB->Reserved3 = 0;
5232 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5233 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005234 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 pSMB->ByteCount = cpu_to_le16(byte_count);
5236
5237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5238 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5239 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005240 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 } else { /* decode response */
5242 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5243
Jeff Layton820a8032011-05-04 08:05:26 -04005244 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 rc = -EIO; /* bad smb */
5246 } else {
5247 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5248 response_data =
5249 (FILE_SYSTEM_UNIX_INFO
5250 *) (((char *) &pSMBr->hdr.Protocol) +
5251 data_offset);
5252 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005253 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 }
5255 }
5256 cifs_buf_release(pSMB);
5257
5258 if (rc == -EAGAIN)
5259 goto QFSUnixRetry;
5260
5261
5262 return rc;
5263}
5264
Jeremy Allisonac670552005-06-22 17:26:35 -07005265int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005266CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005267{
5268/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5269 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5270 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5271 int rc = 0;
5272 int bytes_returned = 0;
5273 __u16 params, param_offset, offset, byte_count;
5274
Joe Perchesf96637b2013-05-04 22:12:25 -05005275 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005276SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005277 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005278 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5279 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005280 if (rc)
5281 return rc;
5282
5283 params = 4; /* 2 bytes zero followed by info level. */
5284 pSMB->MaxSetupCount = 0;
5285 pSMB->Reserved = 0;
5286 pSMB->Flags = 0;
5287 pSMB->Timeout = 0;
5288 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005289 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5290 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005291 offset = param_offset + params;
5292
5293 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005294 /* BB find exact max SMB PDU from sess structure BB */
5295 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005296 pSMB->SetupCount = 1;
5297 pSMB->Reserved3 = 0;
5298 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5299 byte_count = 1 /* pad */ + params + 12;
5300
5301 pSMB->DataCount = cpu_to_le16(12);
5302 pSMB->ParameterCount = cpu_to_le16(params);
5303 pSMB->TotalDataCount = pSMB->DataCount;
5304 pSMB->TotalParameterCount = pSMB->ParameterCount;
5305 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5306 pSMB->DataOffset = cpu_to_le16(offset);
5307
5308 /* Params. */
5309 pSMB->FileNum = 0;
5310 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5311
5312 /* Data. */
5313 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5314 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5315 pSMB->ClientUnixCap = cpu_to_le64(cap);
5316
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005317 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005318 pSMB->ByteCount = cpu_to_le16(byte_count);
5319
5320 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5321 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5322 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005323 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005324 } else { /* decode response */
5325 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005326 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005327 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005328 }
5329 cifs_buf_release(pSMB);
5330
5331 if (rc == -EAGAIN)
5332 goto SETFSUnixRetry;
5333
5334 return rc;
5335}
5336
5337
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338
5339int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005340CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005341 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342{
5343/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5344 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5345 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5346 FILE_SYSTEM_POSIX_INFO *response_data;
5347 int rc = 0;
5348 int bytes_returned = 0;
5349 __u16 params, byte_count;
5350
Joe Perchesf96637b2013-05-04 22:12:25 -05005351 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352QFSPosixRetry:
5353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5354 (void **) &pSMBr);
5355 if (rc)
5356 return rc;
5357
5358 params = 2; /* level */
5359 pSMB->TotalDataCount = 0;
5360 pSMB->DataCount = 0;
5361 pSMB->DataOffset = 0;
5362 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005363 /* BB find exact max SMB PDU from sess structure BB */
5364 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 pSMB->MaxSetupCount = 0;
5366 pSMB->Reserved = 0;
5367 pSMB->Flags = 0;
5368 pSMB->Timeout = 0;
5369 pSMB->Reserved2 = 0;
5370 byte_count = params + 1 /* pad */ ;
5371 pSMB->ParameterCount = cpu_to_le16(params);
5372 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005373 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5374 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 pSMB->SetupCount = 1;
5376 pSMB->Reserved3 = 0;
5377 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5378 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005379 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 pSMB->ByteCount = cpu_to_le16(byte_count);
5381
5382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5384 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005385 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 } else { /* decode response */
5387 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5388
Jeff Layton820a8032011-05-04 08:05:26 -04005389 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 rc = -EIO; /* bad smb */
5391 } else {
5392 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5393 response_data =
5394 (FILE_SYSTEM_POSIX_INFO
5395 *) (((char *) &pSMBr->hdr.Protocol) +
5396 data_offset);
5397 FSData->f_bsize =
5398 le32_to_cpu(response_data->BlockSize);
5399 FSData->f_blocks =
5400 le64_to_cpu(response_data->TotalBlocks);
5401 FSData->f_bfree =
5402 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005403 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 FSData->f_bavail = FSData->f_bfree;
5405 } else {
5406 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005407 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 }
Steve French790fe572007-07-07 19:25:05 +00005409 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005411 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005412 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005414 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 }
5416 }
5417 cifs_buf_release(pSMB);
5418
5419 if (rc == -EAGAIN)
5420 goto QFSPosixRetry;
5421
5422 return rc;
5423}
5424
5425
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005426/*
5427 * We can not use write of zero bytes trick to set file size due to need for
5428 * large file support. Also note that this SetPathInfo is preferred to
5429 * SetFileInfo based method in next routine which is only needed to work around
5430 * a sharing violation bugin Samba which this routine can run into.
5431 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005433CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005434 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5435 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436{
5437 struct smb_com_transaction2_spi_req *pSMB = NULL;
5438 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5439 struct file_end_of_file_info *parm_data;
5440 int name_len;
5441 int rc = 0;
5442 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005443 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5444
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 __u16 params, byte_count, data_count, param_offset, offset;
5446
Joe Perchesf96637b2013-05-04 22:12:25 -05005447 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448SetEOFRetry:
5449 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5450 (void **) &pSMBr);
5451 if (rc)
5452 return rc;
5453
5454 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5455 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005456 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5457 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 name_len++; /* trailing null */
5459 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005460 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005461 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005463 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 }
5465 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005466 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005468 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 pSMB->MaxSetupCount = 0;
5470 pSMB->Reserved = 0;
5471 pSMB->Flags = 0;
5472 pSMB->Timeout = 0;
5473 pSMB->Reserved2 = 0;
5474 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005475 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005477 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005478 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5479 pSMB->InformationLevel =
5480 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5481 else
5482 pSMB->InformationLevel =
5483 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5484 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5486 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005487 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 else
5489 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005490 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 }
5492
5493 parm_data =
5494 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5495 offset);
5496 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5497 pSMB->DataOffset = cpu_to_le16(offset);
5498 pSMB->SetupCount = 1;
5499 pSMB->Reserved3 = 0;
5500 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5501 byte_count = 3 /* pad */ + params + data_count;
5502 pSMB->DataCount = cpu_to_le16(data_count);
5503 pSMB->TotalDataCount = pSMB->DataCount;
5504 pSMB->ParameterCount = cpu_to_le16(params);
5505 pSMB->TotalParameterCount = pSMB->ParameterCount;
5506 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005507 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 parm_data->FileSize = cpu_to_le64(size);
5509 pSMB->ByteCount = cpu_to_le16(byte_count);
5510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5511 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005512 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005513 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514
5515 cifs_buf_release(pSMB);
5516
5517 if (rc == -EAGAIN)
5518 goto SetEOFRetry;
5519
5520 return rc;
5521}
5522
5523int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005524CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5525 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526{
5527 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 struct file_end_of_file_info *parm_data;
5529 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 __u16 params, param_offset, offset, byte_count, count;
5531
Joe Perchesf96637b2013-05-04 22:12:25 -05005532 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5533 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005534 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5535
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 if (rc)
5537 return rc;
5538
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005539 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5540 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005541
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 params = 6;
5543 pSMB->MaxSetupCount = 0;
5544 pSMB->Reserved = 0;
5545 pSMB->Flags = 0;
5546 pSMB->Timeout = 0;
5547 pSMB->Reserved2 = 0;
5548 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5549 offset = param_offset + params;
5550
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 count = sizeof(struct file_end_of_file_info);
5552 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005553 /* BB find exact max SMB PDU from sess structure BB */
5554 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 pSMB->SetupCount = 1;
5556 pSMB->Reserved3 = 0;
5557 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5558 byte_count = 3 /* pad */ + params + count;
5559 pSMB->DataCount = cpu_to_le16(count);
5560 pSMB->ParameterCount = cpu_to_le16(params);
5561 pSMB->TotalDataCount = pSMB->DataCount;
5562 pSMB->TotalParameterCount = pSMB->ParameterCount;
5563 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5564 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005565 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5566 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 pSMB->DataOffset = cpu_to_le16(offset);
5568 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005569 pSMB->Fid = cfile->fid.netfid;
5570 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5572 pSMB->InformationLevel =
5573 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5574 else
5575 pSMB->InformationLevel =
5576 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005577 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5579 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005580 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 else
5582 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005583 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 }
5585 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005586 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005588 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005590 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5591 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 }
5593
Steve French50c2f752007-07-13 00:33:32 +00005594 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 since file handle passed in no longer valid */
5596
5597 return rc;
5598}
5599
Steve French50c2f752007-07-13 00:33:32 +00005600/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 an open handle, rather than by pathname - this is awkward due to
5602 potential access conflicts on the open, but it is unavoidable for these
5603 old servers since the only other choice is to go from 100 nanosecond DCE
5604 time and resort to the original setpathinfo level which takes the ancient
5605 DOS time format with 2 second granularity */
5606int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005607CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005608 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609{
5610 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 char *data_offset;
5612 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 __u16 params, param_offset, offset, byte_count, count;
5614
Joe Perchesf96637b2013-05-04 22:12:25 -05005615 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005616 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5617
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 if (rc)
5619 return rc;
5620
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005621 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5622 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005623
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 params = 6;
5625 pSMB->MaxSetupCount = 0;
5626 pSMB->Reserved = 0;
5627 pSMB->Flags = 0;
5628 pSMB->Timeout = 0;
5629 pSMB->Reserved2 = 0;
5630 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5631 offset = param_offset + params;
5632
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005633 data_offset = (char *)pSMB +
5634 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Steve French26f57362007-08-30 22:09:15 +00005636 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005638 /* BB find max SMB PDU from sess */
5639 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 pSMB->SetupCount = 1;
5641 pSMB->Reserved3 = 0;
5642 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5643 byte_count = 3 /* pad */ + params + count;
5644 pSMB->DataCount = cpu_to_le16(count);
5645 pSMB->ParameterCount = cpu_to_le16(params);
5646 pSMB->TotalDataCount = pSMB->DataCount;
5647 pSMB->TotalParameterCount = pSMB->ParameterCount;
5648 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5649 pSMB->DataOffset = cpu_to_le16(offset);
5650 pSMB->Fid = fid;
5651 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5652 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5653 else
5654 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5655 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005656 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005658 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005659 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005660 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005661 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5662 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663
Steve French50c2f752007-07-13 00:33:32 +00005664 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 since file handle passed in no longer valid */
5666
5667 return rc;
5668}
5669
Jeff Layton6d22f092008-09-23 11:48:35 -04005670int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005671CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005672 bool delete_file, __u16 fid, __u32 pid_of_opener)
5673{
5674 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5675 char *data_offset;
5676 int rc = 0;
5677 __u16 params, param_offset, offset, byte_count, count;
5678
Joe Perchesf96637b2013-05-04 22:12:25 -05005679 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005680 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5681
5682 if (rc)
5683 return rc;
5684
5685 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5686 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5687
5688 params = 6;
5689 pSMB->MaxSetupCount = 0;
5690 pSMB->Reserved = 0;
5691 pSMB->Flags = 0;
5692 pSMB->Timeout = 0;
5693 pSMB->Reserved2 = 0;
5694 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5695 offset = param_offset + params;
5696
5697 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5698
5699 count = 1;
5700 pSMB->MaxParameterCount = cpu_to_le16(2);
5701 /* BB find max SMB PDU from sess */
5702 pSMB->MaxDataCount = cpu_to_le16(1000);
5703 pSMB->SetupCount = 1;
5704 pSMB->Reserved3 = 0;
5705 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5706 byte_count = 3 /* pad */ + params + count;
5707 pSMB->DataCount = cpu_to_le16(count);
5708 pSMB->ParameterCount = cpu_to_le16(params);
5709 pSMB->TotalDataCount = pSMB->DataCount;
5710 pSMB->TotalParameterCount = pSMB->ParameterCount;
5711 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5712 pSMB->DataOffset = cpu_to_le16(offset);
5713 pSMB->Fid = fid;
5714 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5715 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005716 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005717 pSMB->ByteCount = cpu_to_le16(byte_count);
5718 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005719 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005720 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005721 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005722
5723 return rc;
5724}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
5726int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005727CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005728 const char *fileName, const FILE_BASIC_INFO *data,
5729 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730{
5731 TRANSACTION2_SPI_REQ *pSMB = NULL;
5732 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5733 int name_len;
5734 int rc = 0;
5735 int bytes_returned = 0;
5736 char *data_offset;
5737 __u16 params, param_offset, offset, byte_count, count;
5738
Joe Perchesf96637b2013-05-04 22:12:25 -05005739 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740
5741SetTimesRetry:
5742 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5743 (void **) &pSMBr);
5744 if (rc)
5745 return rc;
5746
5747 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5748 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005749 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5750 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 name_len++; /* trailing null */
5752 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005753 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 name_len = strnlen(fileName, PATH_MAX);
5755 name_len++; /* trailing null */
5756 strncpy(pSMB->FileName, fileName, name_len);
5757 }
5758
5759 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005760 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005762 /* BB find max SMB PDU from sess structure BB */
5763 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 pSMB->MaxSetupCount = 0;
5765 pSMB->Reserved = 0;
5766 pSMB->Flags = 0;
5767 pSMB->Timeout = 0;
5768 pSMB->Reserved2 = 0;
5769 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005770 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 offset = param_offset + params;
5772 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5773 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5774 pSMB->DataOffset = cpu_to_le16(offset);
5775 pSMB->SetupCount = 1;
5776 pSMB->Reserved3 = 0;
5777 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5778 byte_count = 3 /* pad */ + params + count;
5779
5780 pSMB->DataCount = cpu_to_le16(count);
5781 pSMB->ParameterCount = cpu_to_le16(params);
5782 pSMB->TotalDataCount = pSMB->DataCount;
5783 pSMB->TotalParameterCount = pSMB->ParameterCount;
5784 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5785 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5786 else
5787 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5788 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005789 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005790 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 pSMB->ByteCount = cpu_to_le16(byte_count);
5792 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5793 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005794 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005795 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796
5797 cifs_buf_release(pSMB);
5798
5799 if (rc == -EAGAIN)
5800 goto SetTimesRetry;
5801
5802 return rc;
5803}
5804
5805/* Can not be used to set time stamps yet (due to old DOS time format) */
5806/* Can be used to set attributes */
5807#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5808 handling it anyway and NT4 was what we thought it would be needed for
5809 Do not delete it until we prove whether needed for Win9x though */
5810int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005811CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 __u16 dos_attrs, const struct nls_table *nls_codepage)
5813{
5814 SETATTR_REQ *pSMB = NULL;
5815 SETATTR_RSP *pSMBr = NULL;
5816 int rc = 0;
5817 int bytes_returned;
5818 int name_len;
5819
Joe Perchesf96637b2013-05-04 22:12:25 -05005820 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821
5822SetAttrLgcyRetry:
5823 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5824 (void **) &pSMBr);
5825 if (rc)
5826 return rc;
5827
5828 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5829 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005830 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5831 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832 name_len++; /* trailing null */
5833 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005834 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 name_len = strnlen(fileName, PATH_MAX);
5836 name_len++; /* trailing null */
5837 strncpy(pSMB->fileName, fileName, name_len);
5838 }
5839 pSMB->attr = cpu_to_le16(dos_attrs);
5840 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005841 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5843 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5844 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005845 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005846 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
5848 cifs_buf_release(pSMB);
5849
5850 if (rc == -EAGAIN)
5851 goto SetAttrLgcyRetry;
5852
5853 return rc;
5854}
5855#endif /* temporarily unneeded SetAttr legacy function */
5856
Jeff Layton654cf142009-07-09 20:02:49 -04005857static void
5858cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5859 const struct cifs_unix_set_info_args *args)
5860{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005861 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005862 u64 mode = args->mode;
5863
Eric W. Biederman49418b22013-02-06 00:57:56 -08005864 if (uid_valid(args->uid))
5865 uid = from_kuid(&init_user_ns, args->uid);
5866 if (gid_valid(args->gid))
5867 gid = from_kgid(&init_user_ns, args->gid);
5868
Jeff Layton654cf142009-07-09 20:02:49 -04005869 /*
5870 * Samba server ignores set of file size to zero due to bugs in some
5871 * older clients, but we should be precise - we use SetFileSize to
5872 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005873 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005874 * zero instead of -1 here
5875 */
5876 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5877 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5878 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5879 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5880 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005881 data_offset->Uid = cpu_to_le64(uid);
5882 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005883 /* better to leave device as zero when it is */
5884 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5885 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5886 data_offset->Permissions = cpu_to_le64(mode);
5887
5888 if (S_ISREG(mode))
5889 data_offset->Type = cpu_to_le32(UNIX_FILE);
5890 else if (S_ISDIR(mode))
5891 data_offset->Type = cpu_to_le32(UNIX_DIR);
5892 else if (S_ISLNK(mode))
5893 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5894 else if (S_ISCHR(mode))
5895 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5896 else if (S_ISBLK(mode))
5897 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5898 else if (S_ISFIFO(mode))
5899 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5900 else if (S_ISSOCK(mode))
5901 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5902}
5903
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005905CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005906 const struct cifs_unix_set_info_args *args,
5907 u16 fid, u32 pid_of_opener)
5908{
5909 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005910 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005911 int rc = 0;
5912 u16 params, param_offset, offset, byte_count, count;
5913
Joe Perchesf96637b2013-05-04 22:12:25 -05005914 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005915 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5916
5917 if (rc)
5918 return rc;
5919
5920 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5921 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5922
5923 params = 6;
5924 pSMB->MaxSetupCount = 0;
5925 pSMB->Reserved = 0;
5926 pSMB->Flags = 0;
5927 pSMB->Timeout = 0;
5928 pSMB->Reserved2 = 0;
5929 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5930 offset = param_offset + params;
5931
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005932 data_offset = (char *)pSMB +
5933 offsetof(struct smb_hdr, Protocol) + offset;
5934
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005935 count = sizeof(FILE_UNIX_BASIC_INFO);
5936
5937 pSMB->MaxParameterCount = cpu_to_le16(2);
5938 /* BB find max SMB PDU from sess */
5939 pSMB->MaxDataCount = cpu_to_le16(1000);
5940 pSMB->SetupCount = 1;
5941 pSMB->Reserved3 = 0;
5942 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5943 byte_count = 3 /* pad */ + params + count;
5944 pSMB->DataCount = cpu_to_le16(count);
5945 pSMB->ParameterCount = cpu_to_le16(params);
5946 pSMB->TotalDataCount = pSMB->DataCount;
5947 pSMB->TotalParameterCount = pSMB->ParameterCount;
5948 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5949 pSMB->DataOffset = cpu_to_le16(offset);
5950 pSMB->Fid = fid;
5951 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5952 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005953 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005954 pSMB->ByteCount = cpu_to_le16(byte_count);
5955
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005956 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005957
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005958 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005959 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005960 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5961 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005962
5963 /* Note: On -EAGAIN error only caller can retry on handle based calls
5964 since file handle passed in no longer valid */
5965
5966 return rc;
5967}
5968
5969int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005970CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005971 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005972 const struct cifs_unix_set_info_args *args,
5973 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974{
5975 TRANSACTION2_SPI_REQ *pSMB = NULL;
5976 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5977 int name_len;
5978 int rc = 0;
5979 int bytes_returned = 0;
5980 FILE_UNIX_BASIC_INFO *data_offset;
5981 __u16 params, param_offset, offset, count, byte_count;
5982
Joe Perchesf96637b2013-05-04 22:12:25 -05005983 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984setPermsRetry:
5985 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5986 (void **) &pSMBr);
5987 if (rc)
5988 return rc;
5989
5990 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5991 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005992 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005993 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 name_len++; /* trailing null */
5995 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005996 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005997 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005999 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 }
6001
6002 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006003 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006005 /* BB find max SMB PDU from sess structure BB */
6006 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 pSMB->MaxSetupCount = 0;
6008 pSMB->Reserved = 0;
6009 pSMB->Flags = 0;
6010 pSMB->Timeout = 0;
6011 pSMB->Reserved2 = 0;
6012 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006013 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 offset = param_offset + params;
6015 data_offset =
6016 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6017 offset);
6018 memset(data_offset, 0, count);
6019 pSMB->DataOffset = cpu_to_le16(offset);
6020 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6021 pSMB->SetupCount = 1;
6022 pSMB->Reserved3 = 0;
6023 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6024 byte_count = 3 /* pad */ + params + count;
6025 pSMB->ParameterCount = cpu_to_le16(params);
6026 pSMB->DataCount = cpu_to_le16(count);
6027 pSMB->TotalParameterCount = pSMB->ParameterCount;
6028 pSMB->TotalDataCount = pSMB->DataCount;
6029 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6030 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006031 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006032
Jeff Layton654cf142009-07-09 20:02:49 -04006033 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034
6035 pSMB->ByteCount = cpu_to_le16(byte_count);
6036 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006038 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006039 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040
Steve French0d817bc2008-05-22 02:02:03 +00006041 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 if (rc == -EAGAIN)
6043 goto setPermsRetry;
6044 return rc;
6045}
6046
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006048/*
6049 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6050 * function used by listxattr and getxattr type calls. When ea_name is set,
6051 * it looks for that attribute name and stuffs that value into the EAData
6052 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6053 * buffer. In both cases, the return value is either the length of the
6054 * resulting data or a negative error code. If EAData is a NULL pointer then
6055 * the data isn't copied to it, but the length is returned.
6056 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006058CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006059 const unsigned char *searchName, const unsigned char *ea_name,
6060 char *EAData, size_t buf_size,
6061 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062{
6063 /* BB assumes one setup word */
6064 TRANSACTION2_QPI_REQ *pSMB = NULL;
6065 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6066 int rc = 0;
6067 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006068 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006069 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006070 struct fea *temp_fea;
6071 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006072 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006073 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006074 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075
Joe Perchesf96637b2013-05-04 22:12:25 -05006076 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077QAllEAsRetry:
6078 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6079 (void **) &pSMBr);
6080 if (rc)
6081 return rc;
6082
6083 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006084 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006085 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6086 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006087 list_len++; /* trailing null */
6088 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006090 list_len = strnlen(searchName, PATH_MAX);
6091 list_len++; /* trailing null */
6092 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 }
6094
Jeff Layton6e462b92010-02-10 16:18:26 -05006095 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 pSMB->TotalDataCount = 0;
6097 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006098 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006099 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 pSMB->MaxSetupCount = 0;
6101 pSMB->Reserved = 0;
6102 pSMB->Flags = 0;
6103 pSMB->Timeout = 0;
6104 pSMB->Reserved2 = 0;
6105 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006106 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107 pSMB->DataCount = 0;
6108 pSMB->DataOffset = 0;
6109 pSMB->SetupCount = 1;
6110 pSMB->Reserved3 = 0;
6111 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6112 byte_count = params + 1 /* pad */ ;
6113 pSMB->TotalParameterCount = cpu_to_le16(params);
6114 pSMB->ParameterCount = pSMB->TotalParameterCount;
6115 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6116 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006117 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 pSMB->ByteCount = cpu_to_le16(byte_count);
6119
6120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6121 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6122 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006123 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006126
6127
6128 /* BB also check enough total bytes returned */
6129 /* BB we need to improve the validity checking
6130 of these trans2 responses */
6131
6132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006133 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006134 rc = -EIO; /* bad smb */
6135 goto QAllEAsOut;
6136 }
6137
6138 /* check that length of list is not more than bcc */
6139 /* check that each entry does not go beyond length
6140 of list */
6141 /* check that each element of each entry does not
6142 go beyond end of list */
6143 /* validate_trans2_offsets() */
6144 /* BB check if start of smb + data_offset > &bcc+ bcc */
6145
6146 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6147 ea_response_data = (struct fealist *)
6148 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6149
Jeff Layton6e462b92010-02-10 16:18:26 -05006150 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006151 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006152 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006153 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006154 goto QAllEAsOut;
6155 }
6156
Jeff Layton0cd126b2010-02-10 16:18:26 -05006157 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006158 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006159 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006160 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006161 rc = -EIO;
6162 goto QAllEAsOut;
6163 }
6164
Jeff Laytonf0d38682010-02-10 16:18:26 -05006165 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006166 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006167 temp_fea = ea_response_data->list;
6168 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006169 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006170 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006171 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006172
Jeff Layton6e462b92010-02-10 16:18:26 -05006173 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006174 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006175 /* make sure we can read name_len and value_len */
6176 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006177 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006178 rc = -EIO;
6179 goto QAllEAsOut;
6180 }
6181
6182 name_len = temp_fea->name_len;
6183 value_len = le16_to_cpu(temp_fea->value_len);
6184 list_len -= name_len + 1 + value_len;
6185 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006186 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006187 rc = -EIO;
6188 goto QAllEAsOut;
6189 }
6190
Jeff Layton31c05192010-02-10 16:18:26 -05006191 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006192 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006193 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006194 temp_ptr += name_len + 1;
6195 rc = value_len;
6196 if (buf_size == 0)
6197 goto QAllEAsOut;
6198 if ((size_t)value_len > buf_size) {
6199 rc = -ERANGE;
6200 goto QAllEAsOut;
6201 }
6202 memcpy(EAData, temp_ptr, value_len);
6203 goto QAllEAsOut;
6204 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006205 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006206 /* account for prefix user. and trailing null */
6207 rc += (5 + 1 + name_len);
6208 if (rc < (int) buf_size) {
6209 memcpy(EAData, "user.", 5);
6210 EAData += 5;
6211 memcpy(EAData, temp_ptr, name_len);
6212 EAData += name_len;
6213 /* null terminate name */
6214 *EAData = 0;
6215 ++EAData;
6216 } else if (buf_size == 0) {
6217 /* skip copy - calc size only */
6218 } else {
6219 /* stop before overrun buffer */
6220 rc = -ERANGE;
6221 break;
6222 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006223 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006224 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006225 temp_fea = (struct fea *)temp_ptr;
6226 }
6227
Jeff Layton31c05192010-02-10 16:18:26 -05006228 /* didn't find the named attribute */
6229 if (ea_name)
6230 rc = -ENODATA;
6231
Jeff Laytonf0d38682010-02-10 16:18:26 -05006232QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006233 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234 if (rc == -EAGAIN)
6235 goto QAllEAsRetry;
6236
6237 return (ssize_t)rc;
6238}
6239
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006241CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6242 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006243 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6244 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245{
6246 struct smb_com_transaction2_spi_req *pSMB = NULL;
6247 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6248 struct fealist *parm_data;
6249 int name_len;
6250 int rc = 0;
6251 int bytes_returned = 0;
6252 __u16 params, param_offset, byte_count, offset, count;
6253
Joe Perchesf96637b2013-05-04 22:12:25 -05006254 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255SetEARetry:
6256 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6257 (void **) &pSMBr);
6258 if (rc)
6259 return rc;
6260
6261 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6262 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006263 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6264 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 name_len++; /* trailing null */
6266 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006267 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268 name_len = strnlen(fileName, PATH_MAX);
6269 name_len++; /* trailing null */
6270 strncpy(pSMB->FileName, fileName, name_len);
6271 }
6272
6273 params = 6 + name_len;
6274
6275 /* done calculating parms using name_len of file name,
6276 now use name_len to calculate length of ea name
6277 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006278 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 name_len = 0;
6280 else
Steve French50c2f752007-07-13 00:33:32 +00006281 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006283 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006285 /* BB find max SMB PDU from sess */
6286 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006287 pSMB->MaxSetupCount = 0;
6288 pSMB->Reserved = 0;
6289 pSMB->Flags = 0;
6290 pSMB->Timeout = 0;
6291 pSMB->Reserved2 = 0;
6292 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006293 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294 offset = param_offset + params;
6295 pSMB->InformationLevel =
6296 cpu_to_le16(SMB_SET_FILE_EA);
6297
6298 parm_data =
6299 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6300 offset);
6301 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6302 pSMB->DataOffset = cpu_to_le16(offset);
6303 pSMB->SetupCount = 1;
6304 pSMB->Reserved3 = 0;
6305 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6306 byte_count = 3 /* pad */ + params + count;
6307 pSMB->DataCount = cpu_to_le16(count);
6308 parm_data->list_len = cpu_to_le32(count);
6309 parm_data->list[0].EA_flags = 0;
6310 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006311 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006313 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006314 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 parm_data->list[0].name[name_len] = 0;
6316 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6317 /* caller ensures that ea_value_len is less than 64K but
6318 we need to ensure that it fits within the smb */
6319
Steve French50c2f752007-07-13 00:33:32 +00006320 /*BB add length check to see if it would fit in
6321 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006322 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6323 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006324 memcpy(parm_data->list[0].name+name_len+1,
6325 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326
6327 pSMB->TotalDataCount = pSMB->DataCount;
6328 pSMB->ParameterCount = cpu_to_le16(params);
6329 pSMB->TotalParameterCount = pSMB->ParameterCount;
6330 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006331 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332 pSMB->ByteCount = cpu_to_le16(byte_count);
6333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006335 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006336 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337
6338 cifs_buf_release(pSMB);
6339
6340 if (rc == -EAGAIN)
6341 goto SetEARetry;
6342
6343 return rc;
6344}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345#endif
Steve French0eff0e22011-02-24 05:39:23 +00006346
6347#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6348/*
6349 * Years ago the kernel added a "dnotify" function for Samba server,
6350 * to allow network clients (such as Windows) to display updated
6351 * lists of files in directory listings automatically when
6352 * files are added by one user when another user has the
6353 * same directory open on their desktop. The Linux cifs kernel
6354 * client hooked into the kernel side of this interface for
6355 * the same reason, but ironically when the VFS moved from
6356 * "dnotify" to "inotify" it became harder to plug in Linux
6357 * network file system clients (the most obvious use case
6358 * for notify interfaces is when multiple users can update
6359 * the contents of the same directory - exactly what network
6360 * file systems can do) although the server (Samba) could
6361 * still use it. For the short term we leave the worker
6362 * function ifdeffed out (below) until inotify is fixed
6363 * in the VFS to make it easier to plug in network file
6364 * system clients. If inotify turns out to be permanently
6365 * incompatible for network fs clients, we could instead simply
6366 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6367 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006368int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006369 const int notify_subdirs, const __u16 netfid,
6370 __u32 filter, struct file *pfile, int multishot,
6371 const struct nls_table *nls_codepage)
6372{
6373 int rc = 0;
6374 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6375 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6376 struct dir_notify_req *dnotify_req;
6377 int bytes_returned;
6378
Joe Perchesf96637b2013-05-04 22:12:25 -05006379 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006380 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6381 (void **) &pSMBr);
6382 if (rc)
6383 return rc;
6384
6385 pSMB->TotalParameterCount = 0 ;
6386 pSMB->TotalDataCount = 0;
6387 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006388 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006389 pSMB->MaxSetupCount = 4;
6390 pSMB->Reserved = 0;
6391 pSMB->ParameterOffset = 0;
6392 pSMB->DataCount = 0;
6393 pSMB->DataOffset = 0;
6394 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6395 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6396 pSMB->ParameterCount = pSMB->TotalParameterCount;
6397 if (notify_subdirs)
6398 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6399 pSMB->Reserved2 = 0;
6400 pSMB->CompletionFilter = cpu_to_le32(filter);
6401 pSMB->Fid = netfid; /* file handle always le */
6402 pSMB->ByteCount = 0;
6403
6404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6405 (struct smb_hdr *)pSMBr, &bytes_returned,
6406 CIFS_ASYNC_OP);
6407 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006408 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006409 } else {
6410 /* Add file to outstanding requests */
6411 /* BB change to kmem cache alloc */
6412 dnotify_req = kmalloc(
6413 sizeof(struct dir_notify_req),
6414 GFP_KERNEL);
6415 if (dnotify_req) {
6416 dnotify_req->Pid = pSMB->hdr.Pid;
6417 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6418 dnotify_req->Mid = pSMB->hdr.Mid;
6419 dnotify_req->Tid = pSMB->hdr.Tid;
6420 dnotify_req->Uid = pSMB->hdr.Uid;
6421 dnotify_req->netfid = netfid;
6422 dnotify_req->pfile = pfile;
6423 dnotify_req->filter = filter;
6424 dnotify_req->multishot = multishot;
6425 spin_lock(&GlobalMid_Lock);
6426 list_add_tail(&dnotify_req->lhead,
6427 &GlobalDnotifyReqList);
6428 spin_unlock(&GlobalMid_Lock);
6429 } else
6430 rc = -ENOMEM;
6431 }
6432 cifs_buf_release(pSMB);
6433 return rc;
6434}
6435#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */