blob: e63961086752fc28bdcd4281aeb9dfb305fd7823 [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 Layton2190eca2013-05-26 07:00:57 -0400618 rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
Jeff Layton9ddec562013-05-26 07:00:58 -0400619 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000620 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000621 /* unknown wct */
622 rc = -EOPNOTSUPP;
623 goto neg_err_exit;
624 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400625 /* else wct == 17, NTLM or better */
626
Steve French96daf2b2011-05-27 04:34:02 +0000627 server->sec_mode = pSMBr->SecurityMode;
628 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500629 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000630
Steve French96daf2b2011-05-27 04:34:02 +0000631 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000632#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000633 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000634#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500635 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000636
Steve French790fe572007-07-07 19:25:05 +0000637 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000638 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000639 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000640 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000641 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000642 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000643 else if (secFlags & CIFSSEC_MAY_KRB5)
644 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000645 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000646 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000647 else if (secFlags & CIFSSEC_MAY_LANMAN)
648 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000649 else {
650 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500651 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000652 goto neg_err_exit;
653 }
654 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000655
Steve French254e55e2006-06-04 05:53:15 +0000656 /* one byte, so no need to convert this or EncryptionKeyLen from
657 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300658 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
659 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400660 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000661 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400662 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000663 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500664 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000665 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000666 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
667 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400668
669 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE)
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500670 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000671 CIFS_CRYPTO_KEY_SIZE);
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400672 else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000673 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400674 (pSMBr->EncryptionKeyLength == 0))
675 rc = decode_ext_sec_blob(server, pSMBr);
676 else if (server->sec_mode & SECMODE_PW_ENCRYPT)
Steve French07cc6cf2011-05-27 04:12:29 +0000677 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400678 else
Steve French254e55e2006-06-04 05:53:15 +0000679 server->capabilities &= ~CAP_EXTENDED_SECURITY;
680
681signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400682 if (!rc)
683 rc = cifs_enable_signing(server, secFlags);
Steve French50c2f752007-07-13 00:33:32 +0000684neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700685 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000686
Joe Perchesf96637b2013-05-04 22:12:25 -0500687 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return rc;
689}
690
691int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400692CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
694 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Joe Perchesf96637b2013-05-04 22:12:25 -0500697 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500698
699 /* BB: do we need to check this? These should never be NULL. */
700 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
701 return -EIO;
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500704 * No need to return error on this operation if tid invalidated and
705 * closed on server already e.g. due to tcp session crashing. Also,
706 * the tcon is no longer on the list, so no need to take lock before
707 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 */
Steve French268875b2009-06-25 00:29:21 +0000709 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000710 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Steve French50c2f752007-07-13 00:33:32 +0000712 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700713 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500714 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return rc;
Steve French133672e2007-11-13 22:41:37 +0000716
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400717 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500719 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Steve French50c2f752007-07-13 00:33:32 +0000721 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500722 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if (rc == -EAGAIN)
724 rc = 0;
725
726 return rc;
727}
728
Jeff Layton766fdbb2011-01-11 07:24:21 -0500729/*
730 * This is a no-op for now. We're not really interested in the reply, but
731 * rather in the fact that the server sent one and that server->lstrp
732 * gets updated.
733 *
734 * FIXME: maybe we should consider checking that the reply matches request?
735 */
736static void
737cifs_echo_callback(struct mid_q_entry *mid)
738{
739 struct TCP_Server_Info *server = mid->callback_data;
740
741 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400742 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500743}
744
745int
746CIFSSMBEcho(struct TCP_Server_Info *server)
747{
748 ECHO_REQ *smb;
749 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400750 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700751 struct smb_rqst rqst = { .rq_iov = &iov,
752 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500753
Joe Perchesf96637b2013-05-04 22:12:25 -0500754 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500755
756 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
757 if (rc)
758 return rc;
759
760 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000761 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500762 smb->hdr.WordCount = 1;
763 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400764 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500765 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000766 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400767 iov.iov_base = smb;
768 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500769
Jeff Laytonfec344e2012-09-18 16:20:35 -0700770 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400771 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500772 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500773 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500774
775 cifs_small_buf_release(smb);
776
777 return rc;
778}
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400781CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 LOGOFF_ANDX_REQ *pSMB;
784 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Joe Perchesf96637b2013-05-04 22:12:25 -0500786 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500787
788 /*
789 * BB: do we need to check validity of ses and server? They should
790 * always be valid since we have an active reference. If not, that
791 * should probably be a BUG()
792 */
793 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return -EIO;
795
Steve Frenchd7b619c2010-02-25 05:36:46 +0000796 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000797 if (ses->need_reconnect)
798 goto session_already_dead; /* no need to send SMBlogoff if uid
799 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
801 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000802 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return rc;
804 }
805
Pavel Shilovsky88257362012-05-23 14:01:59 +0400806 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700807
Steve French96daf2b2011-05-27 04:34:02 +0000808 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
810 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 pSMB->hdr.Uid = ses->Suid;
813
814 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400815 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000816session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000817 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000820 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 error */
822 if (rc == -EAGAIN)
823 rc = 0;
824 return rc;
825}
826
827int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400828CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
829 const char *fileName, __u16 type,
830 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000831{
832 TRANSACTION2_SPI_REQ *pSMB = NULL;
833 TRANSACTION2_SPI_RSP *pSMBr = NULL;
834 struct unlink_psx_rq *pRqD;
835 int name_len;
836 int rc = 0;
837 int bytes_returned = 0;
838 __u16 params, param_offset, offset, byte_count;
839
Joe Perchesf96637b2013-05-04 22:12:25 -0500840 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000841PsxDelete:
842 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
843 (void **) &pSMBr);
844 if (rc)
845 return rc;
846
847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
848 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600849 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
850 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000851 name_len++; /* trailing null */
852 name_len *= 2;
853 } else { /* BB add path length overrun check */
854 name_len = strnlen(fileName, PATH_MAX);
855 name_len++; /* trailing null */
856 strncpy(pSMB->FileName, fileName, name_len);
857 }
858
859 params = 6 + name_len;
860 pSMB->MaxParameterCount = cpu_to_le16(2);
861 pSMB->MaxDataCount = 0; /* BB double check this with jra */
862 pSMB->MaxSetupCount = 0;
863 pSMB->Reserved = 0;
864 pSMB->Flags = 0;
865 pSMB->Timeout = 0;
866 pSMB->Reserved2 = 0;
867 param_offset = offsetof(struct smb_com_transaction2_spi_req,
868 InformationLevel) - 4;
869 offset = param_offset + params;
870
871 /* Setup pointer to Request Data (inode type) */
872 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
873 pRqD->type = cpu_to_le16(type);
874 pSMB->ParameterOffset = cpu_to_le16(param_offset);
875 pSMB->DataOffset = cpu_to_le16(offset);
876 pSMB->SetupCount = 1;
877 pSMB->Reserved3 = 0;
878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
879 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
880
881 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
882 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
883 pSMB->ParameterCount = cpu_to_le16(params);
884 pSMB->TotalParameterCount = pSMB->ParameterCount;
885 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
886 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000887 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000888 pSMB->ByteCount = cpu_to_le16(byte_count);
889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000891 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500892 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000893 cifs_buf_release(pSMB);
894
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400895 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000896
897 if (rc == -EAGAIN)
898 goto PsxDelete;
899
900 return rc;
901}
902
903int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
905 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 DELETE_FILE_REQ *pSMB = NULL;
908 DELETE_FILE_RSP *pSMBr = NULL;
909 int rc = 0;
910 int bytes_returned;
911 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700912 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914DelFileRetry:
915 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
916 (void **) &pSMBr);
917 if (rc)
918 return rc;
919
920 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700921 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
922 PATH_MAX, cifs_sb->local_nls,
923 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 name_len++; /* trailing null */
925 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700926 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700927 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700929 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 }
931 pSMB->SearchAttributes =
932 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
933 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000934 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 pSMB->ByteCount = cpu_to_le16(name_len + 1);
936 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
937 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400938 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000939 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500940 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 cifs_buf_release(pSMB);
943 if (rc == -EAGAIN)
944 goto DelFileRetry;
945
946 return rc;
947}
948
949int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400950CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
951 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
953 DELETE_DIRECTORY_REQ *pSMB = NULL;
954 DELETE_DIRECTORY_RSP *pSMBr = NULL;
955 int rc = 0;
956 int bytes_returned;
957 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400958 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Joe Perchesf96637b2013-05-04 22:12:25 -0500960 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961RmDirRetry:
962 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
963 (void **) &pSMBr);
964 if (rc)
965 return rc;
966
967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400968 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
969 PATH_MAX, cifs_sb->local_nls,
970 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 name_len++; /* trailing null */
972 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700973 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400974 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400976 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978
979 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000980 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 pSMB->ByteCount = cpu_to_le16(name_len + 1);
982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400984 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000985 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500986 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 cifs_buf_release(pSMB);
989 if (rc == -EAGAIN)
990 goto RmDirRetry;
991 return rc;
992}
993
994int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300995CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
996 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
998 int rc = 0;
999 CREATE_DIRECTORY_REQ *pSMB = NULL;
1000 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1001 int bytes_returned;
1002 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001003 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Joe Perchesf96637b2013-05-04 22:12:25 -05001005 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006MkDirRetry:
1007 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1008 (void **) &pSMBr);
1009 if (rc)
1010 return rc;
1011
1012 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001013 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001014 PATH_MAX, cifs_sb->local_nls,
1015 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 name_len++; /* trailing null */
1017 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001018 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 name_len = strnlen(name, PATH_MAX);
1020 name_len++; /* trailing null */
1021 strncpy(pSMB->DirName, name, name_len);
1022 }
1023
1024 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001025 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001029 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001030 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001031 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 cifs_buf_release(pSMB);
1034 if (rc == -EAGAIN)
1035 goto MkDirRetry;
1036 return rc;
1037}
1038
Steve French2dd29d32007-04-23 22:07:35 +00001039int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001040CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1041 __u32 posix_flags, __u64 mode, __u16 *netfid,
1042 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1043 const char *name, const struct nls_table *nls_codepage,
1044 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001045{
1046 TRANSACTION2_SPI_REQ *pSMB = NULL;
1047 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1048 int name_len;
1049 int rc = 0;
1050 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001051 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001052 OPEN_PSX_REQ *pdata;
1053 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001054
Joe Perchesf96637b2013-05-04 22:12:25 -05001055 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001056PsxCreat:
1057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1058 (void **) &pSMBr);
1059 if (rc)
1060 return rc;
1061
1062 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1063 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001064 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1065 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001066 name_len++; /* trailing null */
1067 name_len *= 2;
1068 } else { /* BB improve the check for buffer overruns BB */
1069 name_len = strnlen(name, PATH_MAX);
1070 name_len++; /* trailing null */
1071 strncpy(pSMB->FileName, name, name_len);
1072 }
1073
1074 params = 6 + name_len;
1075 count = sizeof(OPEN_PSX_REQ);
1076 pSMB->MaxParameterCount = cpu_to_le16(2);
1077 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1078 pSMB->MaxSetupCount = 0;
1079 pSMB->Reserved = 0;
1080 pSMB->Flags = 0;
1081 pSMB->Timeout = 0;
1082 pSMB->Reserved2 = 0;
1083 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001084 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001085 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001086 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001087 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001088 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001089 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001090 pdata->OpenFlags = cpu_to_le32(*pOplock);
1091 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1092 pSMB->DataOffset = cpu_to_le16(offset);
1093 pSMB->SetupCount = 1;
1094 pSMB->Reserved3 = 0;
1095 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1096 byte_count = 3 /* pad */ + params + count;
1097
1098 pSMB->DataCount = cpu_to_le16(count);
1099 pSMB->ParameterCount = cpu_to_le16(params);
1100 pSMB->TotalDataCount = pSMB->DataCount;
1101 pSMB->TotalParameterCount = pSMB->ParameterCount;
1102 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1103 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001104 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001105 pSMB->ByteCount = cpu_to_le16(byte_count);
1106 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1107 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1108 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001109 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001110 goto psx_create_err;
1111 }
1112
Joe Perchesf96637b2013-05-04 22:12:25 -05001113 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001114 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1115
Jeff Layton820a8032011-05-04 08:05:26 -04001116 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001117 rc = -EIO; /* bad smb */
1118 goto psx_create_err;
1119 }
1120
1121 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001122 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001123 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001124
Steve French2dd29d32007-04-23 22:07:35 +00001125 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001126 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001127 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1128 /* Let caller know file was created so we can set the mode. */
1129 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001130 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001131 *pOplock |= CIFS_CREATE_ACTION;
1132 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001133 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1134 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001135 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001136 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001137 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001138 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001139 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001140 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001141 goto psx_create_err;
1142 }
Steve French50c2f752007-07-13 00:33:32 +00001143 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001144 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001145 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001146 }
Steve French2dd29d32007-04-23 22:07:35 +00001147
1148psx_create_err:
1149 cifs_buf_release(pSMB);
1150
Steve French65bc98b2009-07-10 15:27:25 +00001151 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001152 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001153 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001154 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001155
1156 if (rc == -EAGAIN)
1157 goto PsxCreat;
1158
Steve French50c2f752007-07-13 00:33:32 +00001159 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001160}
1161
Steve Frencha9d02ad2005-08-24 23:06:05 -07001162static __u16 convert_disposition(int disposition)
1163{
1164 __u16 ofun = 0;
1165
1166 switch (disposition) {
1167 case FILE_SUPERSEDE:
1168 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1169 break;
1170 case FILE_OPEN:
1171 ofun = SMBOPEN_OAPPEND;
1172 break;
1173 case FILE_CREATE:
1174 ofun = SMBOPEN_OCREATE;
1175 break;
1176 case FILE_OPEN_IF:
1177 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1178 break;
1179 case FILE_OVERWRITE:
1180 ofun = SMBOPEN_OTRUNC;
1181 break;
1182 case FILE_OVERWRITE_IF:
1183 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1184 break;
1185 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001186 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 ofun = SMBOPEN_OAPPEND; /* regular open */
1188 }
1189 return ofun;
1190}
1191
Jeff Layton35fc37d2008-05-14 10:22:03 -07001192static int
1193access_flags_to_smbopen_mode(const int access_flags)
1194{
1195 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1196
1197 if (masked_flags == GENERIC_READ)
1198 return SMBOPEN_READ;
1199 else if (masked_flags == GENERIC_WRITE)
1200 return SMBOPEN_WRITE;
1201
1202 /* just go for read/write */
1203 return SMBOPEN_READWRITE;
1204}
1205
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001207SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001209 const int access_flags, const int create_options, __u16 *netfid,
1210 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 const struct nls_table *nls_codepage, int remap)
1212{
1213 int rc = -EACCES;
1214 OPENX_REQ *pSMB = NULL;
1215 OPENX_RSP *pSMBr = NULL;
1216 int bytes_returned;
1217 int name_len;
1218 __u16 count;
1219
1220OldOpenRetry:
1221 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1222 (void **) &pSMBr);
1223 if (rc)
1224 return rc;
1225
1226 pSMB->AndXCommand = 0xFF; /* none */
1227
1228 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1229 count = 1; /* account for one byte pad to word boundary */
1230 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001231 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1232 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 name_len++; /* trailing null */
1234 name_len *= 2;
1235 } else { /* BB improve check for buffer overruns BB */
1236 count = 0; /* no pad */
1237 name_len = strnlen(fileName, PATH_MAX);
1238 name_len++; /* trailing null */
1239 strncpy(pSMB->fileName, fileName, name_len);
1240 }
1241 if (*pOplock & REQ_OPLOCK)
1242 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001243 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001245
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001247 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1249 /* set file as system file if special file such
1250 as fifo and server expecting SFU style and
1251 no Unix extensions */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (create_options & CREATE_OPTION_SPECIAL)
1254 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001255 else /* BB FIXME BB */
1256 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257
Jeff Layton67750fb2008-05-09 22:28:02 +00001258 if (create_options & CREATE_OPTION_READONLY)
1259 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260
1261 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001262/* pSMB->CreateOptions = cpu_to_le32(create_options &
1263 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001265
1266 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001267 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001269 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270
1271 pSMB->ByteCount = cpu_to_le16(count);
1272 /* long_op set to 1 to allow for oplock break timeouts */
1273 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001274 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001275 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001277 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278 } else {
1279 /* BB verify if wct == 15 */
1280
Steve French582d21e2008-05-13 04:54:12 +00001281/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001282
1283 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1284 /* Let caller know file was created so we can set the mode. */
1285 /* Do we care about the CreateAction in any other cases? */
1286 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001287/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001288 *pOplock |= CIFS_CREATE_ACTION; */
1289 /* BB FIXME END */
1290
Steve French790fe572007-07-07 19:25:05 +00001291 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001292 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1293 pfile_info->LastAccessTime = 0; /* BB fixme */
1294 pfile_info->LastWriteTime = 0; /* BB fixme */
1295 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001296 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001297 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001298 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001299 pfile_info->AllocationSize =
1300 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1301 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001302 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001303 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001304 }
1305 }
1306
1307 cifs_buf_release(pSMB);
1308 if (rc == -EAGAIN)
1309 goto OldOpenRetry;
1310 return rc;
1311}
1312
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001314CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001316 const int access_flags, const int create_options, __u16 *netfid,
1317 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001318 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
1320 int rc = -EACCES;
1321 OPEN_REQ *pSMB = NULL;
1322 OPEN_RSP *pSMBr = NULL;
1323 int bytes_returned;
1324 int name_len;
1325 __u16 count;
1326
1327openRetry:
1328 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1329 (void **) &pSMBr);
1330 if (rc)
1331 return rc;
1332
1333 pSMB->AndXCommand = 0xFF; /* none */
1334
1335 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1336 count = 1; /* account for one byte pad to word boundary */
1337 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001338 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1339 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 name_len++; /* trailing null */
1341 name_len *= 2;
1342 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001343 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 count = 0; /* no pad */
1345 name_len = strnlen(fileName, PATH_MAX);
1346 name_len++; /* trailing null */
1347 pSMB->NameLength = cpu_to_le16(name_len);
1348 strncpy(pSMB->fileName, fileName, name_len);
1349 }
1350 if (*pOplock & REQ_OPLOCK)
1351 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001352 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1355 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001356 /* set file as system file if special file such
1357 as fifo and server expecting SFU style and
1358 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001359 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001360 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1361 else
1362 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 /* XP does not handle ATTR_POSIX_SEMANTICS */
1365 /* but it helps speed up case sensitive checks for other
1366 servers such as Samba */
1367 if (tcon->ses->capabilities & CAP_UNIX)
1368 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1369
Jeff Layton67750fb2008-05-09 22:28:02 +00001370 if (create_options & CREATE_OPTION_READONLY)
1371 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1374 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001375 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001376 /* BB Expirement with various impersonation levels and verify */
1377 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 pSMB->SecurityFlags =
1379 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1380
1381 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001382 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 pSMB->ByteCount = cpu_to_le16(count);
1385 /* long_op set to 1 to allow for oplock break timeouts */
1386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001387 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001388 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001390 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 } else {
Steve French09d1db52005-04-28 22:41:08 -07001392 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1394 /* Let caller know file was created so we can set the mode. */
1395 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001396 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001397 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001398 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001399 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1400 36 /* CreationTime to Attributes */);
1401 /* the file_info buf is endian converted by caller */
1402 pfile_info->AllocationSize = pSMBr->AllocationSize;
1403 pfile_info->EndOfFile = pSMBr->EndOfFile;
1404 pfile_info->NumberOfLinks = cpu_to_le32(1);
1405 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 cifs_buf_release(pSMB);
1410 if (rc == -EAGAIN)
1411 goto openRetry;
1412 return rc;
1413}
1414
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001415/*
1416 * Discard any remaining data in the current SMB. To do this, we borrow the
1417 * current bigbuf.
1418 */
1419static int
1420cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1421{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001422 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001423 int remaining = rfclen + 4 - server->total_read;
1424 struct cifs_readdata *rdata = mid->callback_data;
1425
1426 while (remaining > 0) {
1427 int length;
1428
1429 length = cifs_read_from_socket(server, server->bigbuf,
1430 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001431 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432 if (length < 0)
1433 return length;
1434 server->total_read += length;
1435 remaining -= length;
1436 }
1437
1438 dequeue_mid(mid, rdata->result);
1439 return 0;
1440}
1441
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001442int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1444{
1445 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001446 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001447 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001448 char *buf = server->smallbuf;
1449 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450
Joe Perchesf96637b2013-05-04 22:12:25 -05001451 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1452 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453
1454 /*
1455 * read the rest of READ_RSP header (sans Data array), or whatever we
1456 * can if there's not enough data. At this point, we've read down to
1457 * the Mid.
1458 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001459 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001460 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001461
Jeff Layton58195752012-09-19 06:22:34 -07001462 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1463 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001464
Jeff Layton58195752012-09-19 06:22:34 -07001465 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001466 if (length < 0)
1467 return length;
1468 server->total_read += length;
1469
1470 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001471 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001472 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001473 cifs_dbg(FYI, "%s: server returned error %d\n",
1474 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001475 return cifs_readv_discard(server, mid);
1476 }
1477
1478 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001479 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001480 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1481 __func__, server->total_read,
1482 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001483 rdata->result = -EIO;
1484 return cifs_readv_discard(server, mid);
1485 }
1486
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001487 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001488 if (data_offset < server->total_read) {
1489 /*
1490 * win2k8 sometimes sends an offset of 0 when the read
1491 * is beyond the EOF. Treat it as if the data starts just after
1492 * the header.
1493 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001494 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1495 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001496 data_offset = server->total_read;
1497 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1498 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001499 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1500 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001501 rdata->result = -EIO;
1502 return cifs_readv_discard(server, mid);
1503 }
1504
Joe Perchesf96637b2013-05-04 22:12:25 -05001505 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1506 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001507
1508 len = data_offset - server->total_read;
1509 if (len > 0) {
1510 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001511 rdata->iov.iov_base = buf + server->total_read;
1512 rdata->iov.iov_len = len;
1513 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514 if (length < 0)
1515 return length;
1516 server->total_read += length;
1517 }
1518
1519 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001520 rdata->iov.iov_base = buf;
1521 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001522 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1523 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524
1525 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001526 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001527 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528 /* data_len is corrupt -- discard frame */
1529 rdata->result = -EIO;
1530 return cifs_readv_discard(server, mid);
1531 }
1532
Jeff Layton8321fec2012-09-19 06:22:32 -07001533 length = rdata->read_into_pages(server, rdata, data_len);
1534 if (length < 0)
1535 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536
Jeff Layton8321fec2012-09-19 06:22:32 -07001537 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001538 rdata->bytes = length;
1539
Joe Perchesf96637b2013-05-04 22:12:25 -05001540 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1541 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001542
1543 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001544 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545 return cifs_readv_discard(server, mid);
1546
1547 dequeue_mid(mid, false);
1548 return length;
1549}
1550
1551static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001552cifs_readv_callback(struct mid_q_entry *mid)
1553{
1554 struct cifs_readdata *rdata = mid->callback_data;
1555 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1556 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001557 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1558 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001559 .rq_pages = rdata->pages,
1560 .rq_npages = rdata->nr_pages,
1561 .rq_pagesz = rdata->pagesz,
1562 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001563
Joe Perchesf96637b2013-05-04 22:12:25 -05001564 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1565 __func__, mid->mid, mid->mid_state, rdata->result,
1566 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001567
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001568 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001569 case MID_RESPONSE_RECEIVED:
1570 /* result already set, check signature */
1571 if (server->sec_mode &
1572 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff2012-08-03 09:42:45 -05001573 int rc = 0;
1574
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001575 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001576 mid->sequence_number);
Steve French985e4ff2012-08-03 09:42:45 -05001577 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001578 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1579 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001580 }
1581 /* FIXME: should this be counted toward the initiating task? */
1582 task_io_account_read(rdata->bytes);
1583 cifs_stats_bytes_read(tcon, rdata->bytes);
1584 break;
1585 case MID_REQUEST_SUBMITTED:
1586 case MID_RETRY_NEEDED:
1587 rdata->result = -EAGAIN;
1588 break;
1589 default:
1590 rdata->result = -EIO;
1591 }
1592
Jeff Laytonda472fc2012-03-23 14:40:53 -04001593 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001594 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001595 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001596}
1597
1598/* cifs_async_readv - send an async write, and set up mid to handle result */
1599int
1600cifs_async_readv(struct cifs_readdata *rdata)
1601{
1602 int rc;
1603 READ_REQ *smb = NULL;
1604 int wct;
1605 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001606 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001607 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608
Joe Perchesf96637b2013-05-04 22:12:25 -05001609 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1610 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001611
1612 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1613 wct = 12;
1614 else {
1615 wct = 10; /* old style read */
1616 if ((rdata->offset >> 32) > 0) {
1617 /* can not handle this big offset for old */
1618 return -EIO;
1619 }
1620 }
1621
1622 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1623 if (rc)
1624 return rc;
1625
1626 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1627 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1628
1629 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001630 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001631 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1632 if (wct == 12)
1633 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1634 smb->Remaining = 0;
1635 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1636 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1637 if (wct == 12)
1638 smb->ByteCount = 0;
1639 else {
1640 /* old style read */
1641 struct smb_com_readx_req *smbr =
1642 (struct smb_com_readx_req *)smb;
1643 smbr->ByteCount = 0;
1644 }
1645
1646 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001647 rdata->iov.iov_base = smb;
1648 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001649
Jeff Layton6993f742012-05-16 07:13:17 -04001650 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001651 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1652 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001653
1654 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001655 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001656 else
1657 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658
1659 cifs_small_buf_release(smb);
1660 return rc;
1661}
1662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001664CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1665 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666{
1667 int rc = -EACCES;
1668 READ_REQ *pSMB = NULL;
1669 READ_RSP *pSMBr = NULL;
1670 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001671 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001672 int resp_buf_type = 0;
1673 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001674 __u32 pid = io_parms->pid;
1675 __u16 netfid = io_parms->netfid;
1676 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001677 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001678 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
Joe Perchesf96637b2013-05-04 22:12:25 -05001680 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001681 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001682 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001683 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001684 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001685 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001686 /* can not handle this big offset for old */
1687 return -EIO;
1688 }
1689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001692 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (rc)
1694 return rc;
1695
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001696 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1697 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 /* tcon and ses pointer are checked in smb_init */
1700 if (tcon->ses->server == NULL)
1701 return -ECONNABORTED;
1702
Steve Frenchec637e32005-12-12 20:53:18 -08001703 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001705 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001706 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001707 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 pSMB->Remaining = 0;
1710 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1711 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001712 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001713 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1714 else {
1715 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001716 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001717 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001718 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001719 }
Steve Frenchec637e32005-12-12 20:53:18 -08001720
1721 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001722 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001723 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001724 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001725 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001726 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001728 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 } else {
1730 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1731 data_length = data_length << 16;
1732 data_length += le16_to_cpu(pSMBr->DataLength);
1733 *nbytes = data_length;
1734
1735 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001736 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001738 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001739 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 rc = -EIO;
1741 *nbytes = 0;
1742 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001743 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001744 le16_to_cpu(pSMBr->DataOffset);
1745/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001746 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001747 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001748 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001749 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001750 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Steve French4b8f9302006-02-26 16:41:18 +00001754/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001755 if (*buf) {
1756 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001757 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001758 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001759 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001760 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001761 /* return buffer to caller to free */
1762 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001763 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001764 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001765 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001766 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001767 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001768
1769 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 since file handle passed in no longer valid */
1771 return rc;
1772}
1773
Steve Frenchec637e32005-12-12 20:53:18 -08001774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001776CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001777 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001778 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779{
1780 int rc = -EACCES;
1781 WRITE_REQ *pSMB = NULL;
1782 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001783 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 __u32 bytes_sent;
1785 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001786 __u32 pid = io_parms->pid;
1787 __u16 netfid = io_parms->netfid;
1788 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001789 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001790 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Steve Frencha24e2d72010-04-03 17:20:21 +00001792 *nbytes = 0;
1793
Joe Perchesf96637b2013-05-04 22:12:25 -05001794 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001795 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001796 return -ECONNABORTED;
1797
Steve French790fe572007-07-07 19:25:05 +00001798 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001799 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001800 else {
Steve French1c955182005-08-30 20:58:07 -07001801 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001802 if ((offset >> 32) > 0) {
1803 /* can not handle big offset for old srv */
1804 return -EIO;
1805 }
1806 }
Steve French1c955182005-08-30 20:58:07 -07001807
1808 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 (void **) &pSMBr);
1810 if (rc)
1811 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001812
1813 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1814 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1815
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 /* tcon and ses pointer are checked in smb_init */
1817 if (tcon->ses->server == NULL)
1818 return -ECONNABORTED;
1819
1820 pSMB->AndXCommand = 0xFF; /* none */
1821 pSMB->Fid = netfid;
1822 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001823 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001824 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 pSMB->Reserved = 0xFFFFFFFF;
1827 pSMB->WriteMode = 0;
1828 pSMB->Remaining = 0;
1829
Steve French50c2f752007-07-13 00:33:32 +00001830 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 can send more if LARGE_WRITE_X capability returned by the server and if
1832 our buffer is big enough or if we convert to iovecs on socket writes
1833 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001834 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1836 } else {
1837 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1838 & ~0xFF;
1839 }
1840
1841 if (bytes_sent > count)
1842 bytes_sent = count;
1843 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001844 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001845 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001846 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001847 else if (ubuf) {
1848 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 cifs_buf_release(pSMB);
1850 return -EFAULT;
1851 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001852 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 /* No buffer */
1854 cifs_buf_release(pSMB);
1855 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001856 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001857 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001858 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001859 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001860 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1863 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001864 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001865
Steve French790fe572007-07-07 19:25:05 +00001866 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001867 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001868 else { /* old style write has byte count 4 bytes earlier
1869 so 4 bytes pad */
1870 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001871 (struct smb_com_writex_req *)pSMB;
1872 pSMBW->ByteCount = cpu_to_le16(byte_count);
1873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1876 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001877 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001879 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 } else {
1881 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1882 *nbytes = (*nbytes) << 16;
1883 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301884
1885 /*
1886 * Mask off high 16 bits when bytes written as returned by the
1887 * server is greater than bytes requested by the client. Some
1888 * OS/2 servers are known to set incorrect CountHigh values.
1889 */
1890 if (*nbytes > count)
1891 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 }
1893
1894 cifs_buf_release(pSMB);
1895
Steve French50c2f752007-07-13 00:33:32 +00001896 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 since file handle passed in no longer valid */
1898
1899 return rc;
1900}
1901
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001902void
1903cifs_writedata_release(struct kref *refcount)
1904{
1905 struct cifs_writedata *wdata = container_of(refcount,
1906 struct cifs_writedata, refcount);
1907
1908 if (wdata->cfile)
1909 cifsFileInfo_put(wdata->cfile);
1910
1911 kfree(wdata);
1912}
1913
1914/*
1915 * Write failed with a retryable error. Resend the write request. It's also
1916 * possible that the page was redirtied so re-clean the page.
1917 */
1918static void
1919cifs_writev_requeue(struct cifs_writedata *wdata)
1920{
1921 int i, rc;
1922 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001923 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001924
1925 for (i = 0; i < wdata->nr_pages; i++) {
1926 lock_page(wdata->pages[i]);
1927 clear_page_dirty_for_io(wdata->pages[i]);
1928 }
1929
1930 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001931 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1932 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001933 } while (rc == -EAGAIN);
1934
1935 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001936 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001937 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001938 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001939 end_page_writeback(wdata->pages[i]);
1940 page_cache_release(wdata->pages[i]);
1941 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001942 }
1943
1944 mapping_set_error(inode->i_mapping, rc);
1945 kref_put(&wdata->refcount, cifs_writedata_release);
1946}
1947
Jeff Laytonc2e87642012-03-23 14:40:55 -04001948void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001949cifs_writev_complete(struct work_struct *work)
1950{
1951 struct cifs_writedata *wdata = container_of(work,
1952 struct cifs_writedata, work);
1953 struct inode *inode = wdata->cfile->dentry->d_inode;
1954 int i = 0;
1955
1956 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001957 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001958 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001959 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001960 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1961 wdata->bytes);
1962 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1963 return cifs_writev_requeue(wdata);
1964
1965 for (i = 0; i < wdata->nr_pages; i++) {
1966 struct page *page = wdata->pages[i];
1967 if (wdata->result == -EAGAIN)
1968 __set_page_dirty_nobuffers(page);
1969 else if (wdata->result < 0)
1970 SetPageError(page);
1971 end_page_writeback(page);
1972 page_cache_release(page);
1973 }
1974 if (wdata->result != -EAGAIN)
1975 mapping_set_error(inode->i_mapping, wdata->result);
1976 kref_put(&wdata->refcount, cifs_writedata_release);
1977}
1978
1979struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001980cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001981{
1982 struct cifs_writedata *wdata;
1983
1984 /* this would overflow */
1985 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001986 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001987 return NULL;
1988 }
1989
1990 /* writedata + number of page pointers */
1991 wdata = kzalloc(sizeof(*wdata) +
1992 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1993 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001994 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001995 INIT_LIST_HEAD(&wdata->list);
1996 init_completion(&wdata->done);
1997 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001998 }
1999 return wdata;
2000}
2001
2002/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002003 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002004 * workqueue completion task.
2005 */
2006static void
2007cifs_writev_callback(struct mid_q_entry *mid)
2008{
2009 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002010 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002011 unsigned int written;
2012 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2013
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002014 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002015 case MID_RESPONSE_RECEIVED:
2016 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2017 if (wdata->result != 0)
2018 break;
2019
2020 written = le16_to_cpu(smb->CountHigh);
2021 written <<= 16;
2022 written += le16_to_cpu(smb->Count);
2023 /*
2024 * Mask off high 16 bits when bytes written as returned
2025 * by the server is greater than bytes requested by the
2026 * client. OS/2 servers are known to set incorrect
2027 * CountHigh values.
2028 */
2029 if (written > wdata->bytes)
2030 written &= 0xFFFF;
2031
2032 if (written < wdata->bytes)
2033 wdata->result = -ENOSPC;
2034 else
2035 wdata->bytes = written;
2036 break;
2037 case MID_REQUEST_SUBMITTED:
2038 case MID_RETRY_NEEDED:
2039 wdata->result = -EAGAIN;
2040 break;
2041 default:
2042 wdata->result = -EIO;
2043 break;
2044 }
2045
Jeff Laytonda472fc2012-03-23 14:40:53 -04002046 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002047 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002048 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002049}
2050
2051/* cifs_async_writev - send an async write, and set up mid to handle result */
2052int
2053cifs_async_writev(struct cifs_writedata *wdata)
2054{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002055 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002056 WRITE_REQ *smb = NULL;
2057 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002058 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002059 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002060 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002061
2062 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2063 wct = 14;
2064 } else {
2065 wct = 12;
2066 if (wdata->offset >> 32 > 0) {
2067 /* can not handle big offset for old srv */
2068 return -EIO;
2069 }
2070 }
2071
2072 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2073 if (rc)
2074 goto async_writev_out;
2075
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002076 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2077 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002078
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002079 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002080 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002081 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2082 if (wct == 14)
2083 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2084 smb->Reserved = 0xFFFFFFFF;
2085 smb->WriteMode = 0;
2086 smb->Remaining = 0;
2087
2088 smb->DataOffset =
2089 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2090
2091 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002092 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2093 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094
Jeff Laytoneddb0792012-09-18 16:20:35 -07002095 rqst.rq_iov = &iov;
2096 rqst.rq_nvec = 1;
2097 rqst.rq_pages = wdata->pages;
2098 rqst.rq_npages = wdata->nr_pages;
2099 rqst.rq_pagesz = wdata->pagesz;
2100 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101
Joe Perchesf96637b2013-05-04 22:12:25 -05002102 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2103 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002104
2105 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2106 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2107
2108 if (wct == 14) {
2109 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2110 put_bcc(wdata->bytes + 1, &smb->hdr);
2111 } else {
2112 /* wct == 12 */
2113 struct smb_com_writex_req *smbw =
2114 (struct smb_com_writex_req *)smb;
2115 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2116 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002117 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002118 }
2119
2120 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002121 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2122 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002123
2124 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002125 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002126 else
2127 kref_put(&wdata->refcount, cifs_writedata_release);
2128
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002129async_writev_out:
2130 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002131 return rc;
2132}
2133
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002134int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002135CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad722012-09-18 16:20:30 -07002136 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137{
2138 int rc = -EACCES;
2139 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002140 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002141 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002142 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002143 __u32 pid = io_parms->pid;
2144 __u16 netfid = io_parms->netfid;
2145 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002146 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002147 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002149 *nbytes = 0;
2150
Joe Perchesf96637b2013-05-04 22:12:25 -05002151 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002152
Steve French4c3130e2008-12-09 00:28:16 +00002153 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002154 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002155 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002156 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002157 if ((offset >> 32) > 0) {
2158 /* can not handle big offset for old srv */
2159 return -EIO;
2160 }
2161 }
Steve French8cc64c62005-10-03 13:49:43 -07002162 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 if (rc)
2164 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002165
2166 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2167 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2168
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 /* tcon and ses pointer are checked in smb_init */
2170 if (tcon->ses->server == NULL)
2171 return -ECONNABORTED;
2172
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002173 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 pSMB->Fid = netfid;
2175 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002176 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002177 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 pSMB->Reserved = 0xFFFFFFFF;
2179 pSMB->WriteMode = 0;
2180 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002183 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Steve French3e844692005-10-03 13:37:24 -07002185 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2186 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002187 /* header + 1 byte pad */
2188 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002189 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002190 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002191 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002192 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002193 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002194 pSMB->ByteCount = cpu_to_le16(count + 1);
2195 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002196 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002197 (struct smb_com_writex_req *)pSMB;
2198 pSMBW->ByteCount = cpu_to_le16(count + 5);
2199 }
Steve French3e844692005-10-03 13:37:24 -07002200 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002201 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002202 iov[0].iov_len = smb_hdr_len + 4;
2203 else /* wct == 12 pad bigger by four bytes */
2204 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002205
Steve French3e844692005-10-03 13:37:24 -07002206
Pavel Shilovskyba9ad722012-09-18 16:20:30 -07002207 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002208 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002210 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002211 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002212 /* presumably this can not happen, but best to be safe */
2213 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002214 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002215 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002216 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2217 *nbytes = (*nbytes) << 16;
2218 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302219
2220 /*
2221 * Mask off high 16 bits when bytes written as returned by the
2222 * server is greater than bytes requested by the client. OS/2
2223 * servers are known to set incorrect CountHigh values.
2224 */
2225 if (*nbytes > count)
2226 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Steve French4b8f9302006-02-26 16:41:18 +00002229/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002230 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002231 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002232 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002233 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Steve French50c2f752007-07-13 00:33:32 +00002235 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 since file handle passed in no longer valid */
2237
2238 return rc;
2239}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002240
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002241int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2242 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002243 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2244{
2245 int rc = 0;
2246 LOCK_REQ *pSMB = NULL;
2247 struct kvec iov[2];
2248 int resp_buf_type;
2249 __u16 count;
2250
Joe Perchesf96637b2013-05-04 22:12:25 -05002251 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2252 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002253
2254 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2255 if (rc)
2256 return rc;
2257
2258 pSMB->Timeout = 0;
2259 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2260 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2261 pSMB->LockType = lock_type;
2262 pSMB->AndXCommand = 0xFF; /* none */
2263 pSMB->Fid = netfid; /* netfid stays le */
2264
2265 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2266 inc_rfc1001_len(pSMB, count);
2267 pSMB->ByteCount = cpu_to_le16(count);
2268
2269 iov[0].iov_base = (char *)pSMB;
2270 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2271 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2272 iov[1].iov_base = (char *)buf;
2273 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2274
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002275 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002276 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2277 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002278 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002279
2280 return rc;
2281}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002282
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002284CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002285 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002287 const __u32 numLock, const __u8 lockType,
2288 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289{
2290 int rc = 0;
2291 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002292/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002294 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 __u16 count;
2296
Joe Perchesf96637b2013-05-04 22:12:25 -05002297 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2298 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002299 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 if (rc)
2302 return rc;
2303
Steve French790fe572007-07-07 19:25:05 +00002304 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002305 /* no response expected */
2306 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002308 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002309 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2311 } else {
2312 pSMB->Timeout = 0;
2313 }
2314
2315 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2316 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2317 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002318 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 pSMB->AndXCommand = 0xFF; /* none */
2320 pSMB->Fid = smb_file_id; /* netfid stays le */
2321
Steve French790fe572007-07-07 19:25:05 +00002322 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002323 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 /* BB where to store pid high? */
2325 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2326 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2327 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2328 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2329 count = sizeof(LOCKING_ANDX_RANGE);
2330 } else {
2331 /* oplock break */
2332 count = 0;
2333 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002334 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 pSMB->ByteCount = cpu_to_le16(count);
2336
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002337 if (waitFlag) {
2338 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002339 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002340 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002341 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002342 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002343 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002344 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002345 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002346 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002347 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Steve French50c2f752007-07-13 00:33:32 +00002349 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 since file handle passed in no longer valid */
2351 return rc;
2352}
2353
2354int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002355CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002356 const __u16 smb_file_id, const __u32 netpid,
2357 const loff_t start_offset, const __u64 len,
2358 struct file_lock *pLockData, const __u16 lock_type,
2359 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002360{
2361 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2362 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002363 struct cifs_posix_lock *parm_data;
2364 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002365 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002366 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002367 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002368 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002369 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002370
Joe Perchesf96637b2013-05-04 22:12:25 -05002371 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002372
Steve French08547b02006-02-28 22:39:25 +00002373 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2374
2375 if (rc)
2376 return rc;
2377
2378 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2379
Steve French50c2f752007-07-13 00:33:32 +00002380 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002381 pSMB->MaxSetupCount = 0;
2382 pSMB->Reserved = 0;
2383 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002384 pSMB->Reserved2 = 0;
2385 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2386 offset = param_offset + params;
2387
Steve French08547b02006-02-28 22:39:25 +00002388 count = sizeof(struct cifs_posix_lock);
2389 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002390 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002391 pSMB->SetupCount = 1;
2392 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002393 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002394 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2395 else
2396 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2397 byte_count = 3 /* pad */ + params + count;
2398 pSMB->DataCount = cpu_to_le16(count);
2399 pSMB->ParameterCount = cpu_to_le16(params);
2400 pSMB->TotalDataCount = pSMB->DataCount;
2401 pSMB->TotalParameterCount = pSMB->ParameterCount;
2402 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002403 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002404 (((char *) &pSMB->hdr.Protocol) + offset);
2405
2406 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002407 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002408 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002409 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002410 pSMB->Timeout = cpu_to_le32(-1);
2411 } else
2412 pSMB->Timeout = 0;
2413
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002414 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002415 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002416 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002417
2418 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002419 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002420 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2421 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002422 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002423 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002424 if (waitFlag) {
2425 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2426 (struct smb_hdr *) pSMBr, &bytes_returned);
2427 } else {
Steve French133672e2007-11-13 22:41:37 +00002428 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002429 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002430 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2431 &resp_buf_type, timeout);
2432 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2433 not try to free it twice below on exit */
2434 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002435 }
2436
Steve French08547b02006-02-28 22:39:25 +00002437 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002438 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002439 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002440 /* lock structure can be returned on get */
2441 __u16 data_offset;
2442 __u16 data_count;
2443 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002444
Jeff Layton820a8032011-05-04 08:05:26 -04002445 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002446 rc = -EIO; /* bad smb */
2447 goto plk_err_exit;
2448 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002449 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2450 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002451 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002452 rc = -EIO;
2453 goto plk_err_exit;
2454 }
2455 parm_data = (struct cifs_posix_lock *)
2456 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002457 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002458 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002459 else {
2460 if (parm_data->lock_type ==
2461 __constant_cpu_to_le16(CIFS_RDLCK))
2462 pLockData->fl_type = F_RDLCK;
2463 else if (parm_data->lock_type ==
2464 __constant_cpu_to_le16(CIFS_WRLCK))
2465 pLockData->fl_type = F_WRLCK;
2466
Steve French5443d132011-03-13 05:08:25 +00002467 pLockData->fl_start = le64_to_cpu(parm_data->start);
2468 pLockData->fl_end = pLockData->fl_start +
2469 le64_to_cpu(parm_data->length) - 1;
2470 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002471 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002472 }
Steve French50c2f752007-07-13 00:33:32 +00002473
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002474plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002475 if (pSMB)
2476 cifs_small_buf_release(pSMB);
2477
Steve French133672e2007-11-13 22:41:37 +00002478 if (resp_buf_type == CIFS_SMALL_BUFFER)
2479 cifs_small_buf_release(iov[0].iov_base);
2480 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2481 cifs_buf_release(iov[0].iov_base);
2482
Steve French08547b02006-02-28 22:39:25 +00002483 /* Note: On -EAGAIN error only caller can retry on handle based calls
2484 since file handle passed in no longer valid */
2485
2486 return rc;
2487}
2488
2489
2490int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002491CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492{
2493 int rc = 0;
2494 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002495 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
2497/* do not retry on dead session on close */
2498 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002499 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 return 0;
2501 if (rc)
2502 return rc;
2503
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002505 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002507 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002508 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002510 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002512 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 }
2514 }
2515
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002517 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 rc = 0;
2519
2520 return rc;
2521}
2522
2523int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002524CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002525{
2526 int rc = 0;
2527 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002528 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002529
2530 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2531 if (rc)
2532 return rc;
2533
2534 pSMB->FileID = (__u16) smb_file_id;
2535 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002536 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002537 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002538 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002539 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002540
2541 return rc;
2542}
2543
2544int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002545CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002546 const char *from_name, const char *to_name,
2547 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548{
2549 int rc = 0;
2550 RENAME_REQ *pSMB = NULL;
2551 RENAME_RSP *pSMBr = NULL;
2552 int bytes_returned;
2553 int name_len, name_len2;
2554 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002555 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
Joe Perchesf96637b2013-05-04 22:12:25 -05002557 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558renameRetry:
2559 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2560 (void **) &pSMBr);
2561 if (rc)
2562 return rc;
2563
2564 pSMB->BufferFormat = 0x04;
2565 pSMB->SearchAttributes =
2566 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2567 ATTR_DIRECTORY);
2568
2569 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002570 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2571 from_name, PATH_MAX,
2572 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 name_len++; /* trailing null */
2574 name_len *= 2;
2575 pSMB->OldFileName[name_len] = 0x04; /* pad */
2576 /* protocol requires ASCII signature byte on Unicode string */
2577 pSMB->OldFileName[name_len + 1] = 0x00;
2578 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002579 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002580 to_name, PATH_MAX, cifs_sb->local_nls,
2581 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2583 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002584 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002585 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002587 strncpy(pSMB->OldFileName, from_name, name_len);
2588 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 name_len2++; /* trailing null */
2590 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002591 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 name_len2++; /* trailing null */
2593 name_len2++; /* signature byte */
2594 }
2595
2596 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002597 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 pSMB->ByteCount = cpu_to_le16(count);
2599
2600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002602 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002603 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002604 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 cifs_buf_release(pSMB);
2607
2608 if (rc == -EAGAIN)
2609 goto renameRetry;
2610
2611 return rc;
2612}
2613
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002614int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002615 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002616 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617{
2618 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2619 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002620 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 char *data_offset;
2622 char dummy_string[30];
2623 int rc = 0;
2624 int bytes_returned = 0;
2625 int len_of_str;
2626 __u16 params, param_offset, offset, count, byte_count;
2627
Joe Perchesf96637b2013-05-04 22:12:25 -05002628 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2630 (void **) &pSMBr);
2631 if (rc)
2632 return rc;
2633
2634 params = 6;
2635 pSMB->MaxSetupCount = 0;
2636 pSMB->Reserved = 0;
2637 pSMB->Flags = 0;
2638 pSMB->Timeout = 0;
2639 pSMB->Reserved2 = 0;
2640 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2641 offset = param_offset + params;
2642
2643 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2644 rename_info = (struct set_file_rename *) data_offset;
2645 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002646 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 pSMB->SetupCount = 1;
2648 pSMB->Reserved3 = 0;
2649 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2650 byte_count = 3 /* pad */ + params;
2651 pSMB->ParameterCount = cpu_to_le16(params);
2652 pSMB->TotalParameterCount = pSMB->ParameterCount;
2653 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2654 pSMB->DataOffset = cpu_to_le16(offset);
2655 /* construct random name ".cifs_tmp<inodenum><mid>" */
2656 rename_info->overwrite = cpu_to_le32(1);
2657 rename_info->root_fid = 0;
2658 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002659 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002660 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002661 len_of_str =
2662 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002663 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002665 len_of_str =
2666 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002667 target_name, PATH_MAX, nls_codepage,
2668 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 }
2670 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002671 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 byte_count += count;
2673 pSMB->DataCount = cpu_to_le16(count);
2674 pSMB->TotalDataCount = pSMB->DataCount;
2675 pSMB->Fid = netfid;
2676 pSMB->InformationLevel =
2677 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2678 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002679 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 pSMB->ByteCount = cpu_to_le16(byte_count);
2681 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002683 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002684 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002685 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2686 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002687
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 cifs_buf_release(pSMB);
2689
2690 /* Note: On -EAGAIN error only caller can retry on handle based calls
2691 since file handle passed in no longer valid */
2692
2693 return rc;
2694}
2695
2696int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002697CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2698 const char *fromName, const __u16 target_tid, const char *toName,
2699 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
2701 int rc = 0;
2702 COPY_REQ *pSMB = NULL;
2703 COPY_RSP *pSMBr = NULL;
2704 int bytes_returned;
2705 int name_len, name_len2;
2706 __u16 count;
2707
Joe Perchesf96637b2013-05-04 22:12:25 -05002708 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709copyRetry:
2710 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2711 (void **) &pSMBr);
2712 if (rc)
2713 return rc;
2714
2715 pSMB->BufferFormat = 0x04;
2716 pSMB->Tid2 = target_tid;
2717
2718 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2719
2720 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002721 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2722 fromName, PATH_MAX, nls_codepage,
2723 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 name_len++; /* trailing null */
2725 name_len *= 2;
2726 pSMB->OldFileName[name_len] = 0x04; /* pad */
2727 /* protocol requires ASCII signature byte on Unicode string */
2728 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002729 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002730 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2731 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2733 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002734 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 name_len = strnlen(fromName, PATH_MAX);
2736 name_len++; /* trailing null */
2737 strncpy(pSMB->OldFileName, fromName, name_len);
2738 name_len2 = strnlen(toName, PATH_MAX);
2739 name_len2++; /* trailing null */
2740 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2741 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2742 name_len2++; /* trailing null */
2743 name_len2++; /* signature byte */
2744 }
2745
2746 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002747 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 pSMB->ByteCount = cpu_to_le16(count);
2749
2750 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2751 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2752 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002753 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2754 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 }
Steve French0d817bc2008-05-22 02:02:03 +00002756 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757
2758 if (rc == -EAGAIN)
2759 goto copyRetry;
2760
2761 return rc;
2762}
2763
2764int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002765CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 const char *fromName, const char *toName,
2767 const struct nls_table *nls_codepage)
2768{
2769 TRANSACTION2_SPI_REQ *pSMB = NULL;
2770 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2771 char *data_offset;
2772 int name_len;
2773 int name_len_target;
2774 int rc = 0;
2775 int bytes_returned = 0;
2776 __u16 params, param_offset, offset, byte_count;
2777
Joe Perchesf96637b2013-05-04 22:12:25 -05002778 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779createSymLinkRetry:
2780 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2781 (void **) &pSMBr);
2782 if (rc)
2783 return rc;
2784
2785 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2786 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002787 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2788 /* find define for this maxpathcomponent */
2789 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 name_len++; /* trailing null */
2791 name_len *= 2;
2792
Steve French50c2f752007-07-13 00:33:32 +00002793 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 name_len = strnlen(fromName, PATH_MAX);
2795 name_len++; /* trailing null */
2796 strncpy(pSMB->FileName, fromName, name_len);
2797 }
2798 params = 6 + name_len;
2799 pSMB->MaxSetupCount = 0;
2800 pSMB->Reserved = 0;
2801 pSMB->Flags = 0;
2802 pSMB->Timeout = 0;
2803 pSMB->Reserved2 = 0;
2804 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002805 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 offset = param_offset + params;
2807
2808 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2810 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002811 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2812 /* find define for this maxpathcomponent */
2813 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 name_len_target++; /* trailing null */
2815 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002816 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len_target = strnlen(toName, PATH_MAX);
2818 name_len_target++; /* trailing null */
2819 strncpy(data_offset, toName, name_len_target);
2820 }
2821
2822 pSMB->MaxParameterCount = cpu_to_le16(2);
2823 /* BB find exact max on data count below from sess */
2824 pSMB->MaxDataCount = cpu_to_le16(1000);
2825 pSMB->SetupCount = 1;
2826 pSMB->Reserved3 = 0;
2827 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2828 byte_count = 3 /* pad */ + params + name_len_target;
2829 pSMB->DataCount = cpu_to_le16(name_len_target);
2830 pSMB->ParameterCount = cpu_to_le16(params);
2831 pSMB->TotalDataCount = pSMB->DataCount;
2832 pSMB->TotalParameterCount = pSMB->ParameterCount;
2833 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2834 pSMB->DataOffset = cpu_to_le16(offset);
2835 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2836 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002837 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 pSMB->ByteCount = cpu_to_le16(byte_count);
2839 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2840 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002841 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002842 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002843 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2844 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
Steve French0d817bc2008-05-22 02:02:03 +00002846 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
2848 if (rc == -EAGAIN)
2849 goto createSymLinkRetry;
2850
2851 return rc;
2852}
2853
2854int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002855CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002857 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858{
2859 TRANSACTION2_SPI_REQ *pSMB = NULL;
2860 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2861 char *data_offset;
2862 int name_len;
2863 int name_len_target;
2864 int rc = 0;
2865 int bytes_returned = 0;
2866 __u16 params, param_offset, offset, byte_count;
2867
Joe Perchesf96637b2013-05-04 22:12:25 -05002868 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869createHardLinkRetry:
2870 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2871 (void **) &pSMBr);
2872 if (rc)
2873 return rc;
2874
2875 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002876 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2877 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 name_len++; /* trailing null */
2879 name_len *= 2;
2880
Steve French50c2f752007-07-13 00:33:32 +00002881 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 name_len = strnlen(toName, PATH_MAX);
2883 name_len++; /* trailing null */
2884 strncpy(pSMB->FileName, toName, name_len);
2885 }
2886 params = 6 + name_len;
2887 pSMB->MaxSetupCount = 0;
2888 pSMB->Reserved = 0;
2889 pSMB->Flags = 0;
2890 pSMB->Timeout = 0;
2891 pSMB->Reserved2 = 0;
2892 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002893 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 offset = param_offset + params;
2895
2896 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2898 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002899 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2900 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 name_len_target++; /* trailing null */
2902 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002903 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 name_len_target = strnlen(fromName, PATH_MAX);
2905 name_len_target++; /* trailing null */
2906 strncpy(data_offset, fromName, name_len_target);
2907 }
2908
2909 pSMB->MaxParameterCount = cpu_to_le16(2);
2910 /* BB find exact max on data count below from sess*/
2911 pSMB->MaxDataCount = cpu_to_le16(1000);
2912 pSMB->SetupCount = 1;
2913 pSMB->Reserved3 = 0;
2914 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2915 byte_count = 3 /* pad */ + params + name_len_target;
2916 pSMB->ParameterCount = cpu_to_le16(params);
2917 pSMB->TotalParameterCount = pSMB->ParameterCount;
2918 pSMB->DataCount = cpu_to_le16(name_len_target);
2919 pSMB->TotalDataCount = pSMB->DataCount;
2920 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2921 pSMB->DataOffset = cpu_to_le16(offset);
2922 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2923 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002924 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 pSMB->ByteCount = cpu_to_le16(byte_count);
2926 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2927 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002928 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002929 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002930 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2931 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932
2933 cifs_buf_release(pSMB);
2934 if (rc == -EAGAIN)
2935 goto createHardLinkRetry;
2936
2937 return rc;
2938}
2939
2940int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002941CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002942 const char *from_name, const char *to_name,
2943 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944{
2945 int rc = 0;
2946 NT_RENAME_REQ *pSMB = NULL;
2947 RENAME_RSP *pSMBr = NULL;
2948 int bytes_returned;
2949 int name_len, name_len2;
2950 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002951 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
Joe Perchesf96637b2013-05-04 22:12:25 -05002953 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954winCreateHardLinkRetry:
2955
2956 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2957 (void **) &pSMBr);
2958 if (rc)
2959 return rc;
2960
2961 pSMB->SearchAttributes =
2962 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2963 ATTR_DIRECTORY);
2964 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2965 pSMB->ClusterCount = 0;
2966
2967 pSMB->BufferFormat = 0x04;
2968
2969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2970 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002971 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2972 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 name_len++; /* trailing null */
2974 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002975
2976 /* protocol specifies ASCII buffer format (0x04) for unicode */
2977 pSMB->OldFileName[name_len] = 0x04;
2978 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002980 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002981 to_name, PATH_MAX, cifs_sb->local_nls,
2982 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2984 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002985 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002986 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002988 strncpy(pSMB->OldFileName, from_name, name_len);
2989 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 name_len2++; /* trailing null */
2991 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002992 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 name_len2++; /* trailing null */
2994 name_len2++; /* signature byte */
2995 }
2996
2997 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002998 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 pSMB->ByteCount = cpu_to_le16(count);
3000
3001 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3002 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003003 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003004 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003005 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003006
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 cifs_buf_release(pSMB);
3008 if (rc == -EAGAIN)
3009 goto winCreateHardLinkRetry;
3010
3011 return rc;
3012}
3013
3014int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003015CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003016 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 const struct nls_table *nls_codepage)
3018{
3019/* SMB_QUERY_FILE_UNIX_LINK */
3020 TRANSACTION2_QPI_REQ *pSMB = NULL;
3021 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3022 int rc = 0;
3023 int bytes_returned;
3024 int name_len;
3025 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003026 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027
Joe Perchesf96637b2013-05-04 22:12:25 -05003028 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
3030querySymLinkRetry:
3031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3032 (void **) &pSMBr);
3033 if (rc)
3034 return rc;
3035
3036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3037 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003038 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3039 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 name_len++; /* trailing null */
3041 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003042 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 name_len = strnlen(searchName, PATH_MAX);
3044 name_len++; /* trailing null */
3045 strncpy(pSMB->FileName, searchName, name_len);
3046 }
3047
3048 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3049 pSMB->TotalDataCount = 0;
3050 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003051 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 pSMB->MaxSetupCount = 0;
3053 pSMB->Reserved = 0;
3054 pSMB->Flags = 0;
3055 pSMB->Timeout = 0;
3056 pSMB->Reserved2 = 0;
3057 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003058 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 pSMB->DataCount = 0;
3060 pSMB->DataOffset = 0;
3061 pSMB->SetupCount = 1;
3062 pSMB->Reserved3 = 0;
3063 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3064 byte_count = params + 1 /* pad */ ;
3065 pSMB->TotalParameterCount = cpu_to_le16(params);
3066 pSMB->ParameterCount = pSMB->TotalParameterCount;
3067 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3068 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003069 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 pSMB->ByteCount = cpu_to_le16(byte_count);
3071
3072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3074 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003075 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 } else {
3077 /* decode response */
3078
3079 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003081 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003082 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003084 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003085 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
Jeff Layton460b9692009-04-30 07:17:56 -04003087 data_start = ((char *) &pSMBr->hdr.Protocol) +
3088 le16_to_cpu(pSMBr->t2.DataOffset);
3089
Steve French0e0d2cf2009-05-01 05:27:32 +00003090 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3091 is_unicode = true;
3092 else
3093 is_unicode = false;
3094
Steve French737b7582005-04-28 22:41:06 -07003095 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003096 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3097 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003098 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003099 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 }
3101 }
3102 cifs_buf_release(pSMB);
3103 if (rc == -EAGAIN)
3104 goto querySymLinkRetry;
3105 return rc;
3106}
3107
Steve Frenchc52a9552011-02-24 06:16:22 +00003108#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3109/*
3110 * Recent Windows versions now create symlinks more frequently
3111 * and they use the "reparse point" mechanism below. We can of course
3112 * do symlinks nicely to Samba and other servers which support the
3113 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3114 * "MF" symlinks optionally, but for recent Windows we really need to
3115 * reenable the code below and fix the cifs_symlink callers to handle this.
3116 * In the interim this code has been moved to its own config option so
3117 * it is not compiled in by default until callers fixed up and more tested.
3118 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003120CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003122 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 const struct nls_table *nls_codepage)
3124{
3125 int rc = 0;
3126 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003127 struct smb_com_transaction_ioctl_req *pSMB;
3128 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129
Joe Perchesf96637b2013-05-04 22:12:25 -05003130 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3131 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3133 (void **) &pSMBr);
3134 if (rc)
3135 return rc;
3136
3137 pSMB->TotalParameterCount = 0 ;
3138 pSMB->TotalDataCount = 0;
3139 pSMB->MaxParameterCount = cpu_to_le32(2);
3140 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003141 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 pSMB->MaxSetupCount = 4;
3143 pSMB->Reserved = 0;
3144 pSMB->ParameterOffset = 0;
3145 pSMB->DataCount = 0;
3146 pSMB->DataOffset = 0;
3147 pSMB->SetupCount = 4;
3148 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3149 pSMB->ParameterCount = pSMB->TotalParameterCount;
3150 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3151 pSMB->IsFsctl = 1; /* FSCTL */
3152 pSMB->IsRootFlag = 0;
3153 pSMB->Fid = fid; /* file handle always le */
3154 pSMB->ByteCount = 0;
3155
3156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3157 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3158 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003159 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 } else { /* decode response */
3161 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3162 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003163 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3164 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003166 goto qreparse_out;
3167 }
3168 if (data_count && (data_count < 2048)) {
3169 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003170 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
Steve Frenchafe48c32009-05-02 05:25:46 +00003172 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003173 (struct reparse_data *)
3174 ((char *)&pSMBr->hdr.Protocol
3175 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003176 if ((char *)reparse_buf >= end_of_smb) {
3177 rc = -EIO;
3178 goto qreparse_out;
3179 }
3180 if ((reparse_buf->LinkNamesBuf +
3181 reparse_buf->TargetNameOffset +
3182 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003183 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003184 rc = -EIO;
3185 goto qreparse_out;
3186 }
Steve French50c2f752007-07-13 00:33:32 +00003187
Steve Frenchafe48c32009-05-02 05:25:46 +00003188 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3189 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003190 (reparse_buf->LinkNamesBuf +
3191 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003192 buflen,
3193 reparse_buf->TargetNameLen,
3194 nls_codepage, 0);
3195 } else { /* ASCII names */
3196 strncpy(symlinkinfo,
3197 reparse_buf->LinkNamesBuf +
3198 reparse_buf->TargetNameOffset,
3199 min_t(const int, buflen,
3200 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003202 } else {
3203 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003204 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003206 symlinkinfo[buflen] = 0; /* just in case so the caller
3207 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003208 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 }
Steve French989c7e52009-05-02 05:32:20 +00003210
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003212 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
3214 /* Note: On -EAGAIN error only caller can retry on handle based calls
3215 since file handle passed in no longer valid */
3216
3217 return rc;
3218}
Steve Frenchc52a9552011-02-24 06:16:22 +00003219#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
3221#ifdef CONFIG_CIFS_POSIX
3222
3223/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003224static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3225 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226{
3227 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003228 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3229 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3230 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003231/*
3232 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3233 ace->e_perm, ace->e_tag, ace->e_id);
3234*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235
3236 return;
3237}
3238
3239/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003240static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3241 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242{
3243 int size = 0;
3244 int i;
3245 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003246 struct cifs_posix_ace *pACE;
3247 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3248 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
3250 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3251 return -EOPNOTSUPP;
3252
Steve French790fe572007-07-07 19:25:05 +00003253 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 count = le16_to_cpu(cifs_acl->access_entry_count);
3255 pACE = &cifs_acl->ace_array[0];
3256 size = sizeof(struct cifs_posix_acl);
3257 size += sizeof(struct cifs_posix_ace) * count;
3258 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003259 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003260 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3261 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 return -EINVAL;
3263 }
Steve French790fe572007-07-07 19:25:05 +00003264 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 count = le16_to_cpu(cifs_acl->access_entry_count);
3266 size = sizeof(struct cifs_posix_acl);
3267 size += sizeof(struct cifs_posix_ace) * count;
3268/* skip past access ACEs to get to default ACEs */
3269 pACE = &cifs_acl->ace_array[count];
3270 count = le16_to_cpu(cifs_acl->default_entry_count);
3271 size += sizeof(struct cifs_posix_ace) * count;
3272 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003273 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 return -EINVAL;
3275 } else {
3276 /* illegal type */
3277 return -EINVAL;
3278 }
3279
3280 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003281 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003282 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003283 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 return -ERANGE;
3285 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003286 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003287 for (i = 0; i < count ; i++) {
3288 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3289 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 }
3291 }
3292 return size;
3293}
3294
Steve French50c2f752007-07-13 00:33:32 +00003295static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3296 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297{
3298 __u16 rc = 0; /* 0 = ACL converted ok */
3299
Steve Frenchff7feac2005-11-15 16:45:16 -08003300 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3301 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003303 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 /* Probably no need to le convert -1 on any arch but can not hurt */
3305 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003306 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003307 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003308/*
3309 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3310 ace->e_perm, ace->e_tag, ace->e_id);
3311*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 return rc;
3313}
3314
3315/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003316static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3317 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318{
3319 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003320 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3321 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 int count;
3323 int i;
3324
Steve French790fe572007-07-07 19:25:05 +00003325 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 return 0;
3327
3328 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003329 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3330 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003331 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003332 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3333 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 return 0;
3335 }
3336 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003337 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003338 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003339 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003340 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003342 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 return 0;
3344 }
Steve French50c2f752007-07-13 00:33:32 +00003345 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3347 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003348 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 /* ACE not converted */
3350 break;
3351 }
3352 }
Steve French790fe572007-07-07 19:25:05 +00003353 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3355 rc += sizeof(struct cifs_posix_acl);
3356 /* BB add check to make sure ACL does not overflow SMB */
3357 }
3358 return rc;
3359}
3360
3361int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003362CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003363 const unsigned char *searchName,
3364 char *acl_inf, const int buflen, const int acl_type,
3365 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366{
3367/* SMB_QUERY_POSIX_ACL */
3368 TRANSACTION2_QPI_REQ *pSMB = NULL;
3369 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3370 int rc = 0;
3371 int bytes_returned;
3372 int name_len;
3373 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003374
Joe Perchesf96637b2013-05-04 22:12:25 -05003375 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376
3377queryAclRetry:
3378 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3379 (void **) &pSMBr);
3380 if (rc)
3381 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003382
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3384 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003385 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3386 searchName, PATH_MAX, nls_codepage,
3387 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 name_len++; /* trailing null */
3389 name_len *= 2;
3390 pSMB->FileName[name_len] = 0;
3391 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003392 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 name_len = strnlen(searchName, PATH_MAX);
3394 name_len++; /* trailing null */
3395 strncpy(pSMB->FileName, searchName, name_len);
3396 }
3397
3398 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3399 pSMB->TotalDataCount = 0;
3400 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003401 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 pSMB->MaxDataCount = cpu_to_le16(4000);
3403 pSMB->MaxSetupCount = 0;
3404 pSMB->Reserved = 0;
3405 pSMB->Flags = 0;
3406 pSMB->Timeout = 0;
3407 pSMB->Reserved2 = 0;
3408 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003409 offsetof(struct smb_com_transaction2_qpi_req,
3410 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 pSMB->DataCount = 0;
3412 pSMB->DataOffset = 0;
3413 pSMB->SetupCount = 1;
3414 pSMB->Reserved3 = 0;
3415 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3416 byte_count = params + 1 /* pad */ ;
3417 pSMB->TotalParameterCount = cpu_to_le16(params);
3418 pSMB->ParameterCount = pSMB->TotalParameterCount;
3419 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3420 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003421 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 pSMB->ByteCount = cpu_to_le16(byte_count);
3423
3424 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003426 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003428 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 } else {
3430 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003431
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003434 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 rc = -EIO; /* bad smb */
3436 else {
3437 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3438 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3439 rc = cifs_copy_posix_acl(acl_inf,
3440 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003441 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 }
3443 }
3444 cifs_buf_release(pSMB);
3445 if (rc == -EAGAIN)
3446 goto queryAclRetry;
3447 return rc;
3448}
3449
3450int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003451CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003452 const unsigned char *fileName,
3453 const char *local_acl, const int buflen,
3454 const int acl_type,
3455 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456{
3457 struct smb_com_transaction2_spi_req *pSMB = NULL;
3458 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3459 char *parm_data;
3460 int name_len;
3461 int rc = 0;
3462 int bytes_returned = 0;
3463 __u16 params, byte_count, data_count, param_offset, offset;
3464
Joe Perchesf96637b2013-05-04 22:12:25 -05003465 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466setAclRetry:
3467 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003468 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 if (rc)
3470 return rc;
3471 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3472 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003473 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3474 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 name_len++; /* trailing null */
3476 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003477 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 name_len = strnlen(fileName, PATH_MAX);
3479 name_len++; /* trailing null */
3480 strncpy(pSMB->FileName, fileName, name_len);
3481 }
3482 params = 6 + name_len;
3483 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003484 /* BB find max SMB size from sess */
3485 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 pSMB->MaxSetupCount = 0;
3487 pSMB->Reserved = 0;
3488 pSMB->Flags = 0;
3489 pSMB->Timeout = 0;
3490 pSMB->Reserved2 = 0;
3491 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003492 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 offset = param_offset + params;
3494 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3495 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3496
3497 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003498 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
Steve French790fe572007-07-07 19:25:05 +00003500 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 rc = -EOPNOTSUPP;
3502 goto setACLerrorExit;
3503 }
3504 pSMB->DataOffset = cpu_to_le16(offset);
3505 pSMB->SetupCount = 1;
3506 pSMB->Reserved3 = 0;
3507 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3508 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3509 byte_count = 3 /* pad */ + params + data_count;
3510 pSMB->DataCount = cpu_to_le16(data_count);
3511 pSMB->TotalDataCount = pSMB->DataCount;
3512 pSMB->ParameterCount = cpu_to_le16(params);
3513 pSMB->TotalParameterCount = pSMB->ParameterCount;
3514 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003515 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 pSMB->ByteCount = cpu_to_le16(byte_count);
3517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003518 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003519 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003520 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
3522setACLerrorExit:
3523 cifs_buf_release(pSMB);
3524 if (rc == -EAGAIN)
3525 goto setAclRetry;
3526 return rc;
3527}
3528
Steve Frenchf654bac2005-04-28 22:41:04 -07003529/* BB fix tabs in this function FIXME BB */
3530int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003531CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003532 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003533{
Steve French50c2f752007-07-13 00:33:32 +00003534 int rc = 0;
3535 struct smb_t2_qfi_req *pSMB = NULL;
3536 struct smb_t2_qfi_rsp *pSMBr = NULL;
3537 int bytes_returned;
3538 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003539
Joe Perchesf96637b2013-05-04 22:12:25 -05003540 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003541 if (tcon == NULL)
3542 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003543
3544GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003545 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3546 (void **) &pSMBr);
3547 if (rc)
3548 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003549
Steve Frenchad7a2922008-02-07 23:25:02 +00003550 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003551 pSMB->t2.TotalDataCount = 0;
3552 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3553 /* BB find exact max data count below from sess structure BB */
3554 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3555 pSMB->t2.MaxSetupCount = 0;
3556 pSMB->t2.Reserved = 0;
3557 pSMB->t2.Flags = 0;
3558 pSMB->t2.Timeout = 0;
3559 pSMB->t2.Reserved2 = 0;
3560 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3561 Fid) - 4);
3562 pSMB->t2.DataCount = 0;
3563 pSMB->t2.DataOffset = 0;
3564 pSMB->t2.SetupCount = 1;
3565 pSMB->t2.Reserved3 = 0;
3566 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3567 byte_count = params + 1 /* pad */ ;
3568 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3569 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3570 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3571 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003572 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003573 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003574 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003575
Steve French790fe572007-07-07 19:25:05 +00003576 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3577 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3578 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003579 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003580 } else {
3581 /* decode response */
3582 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003583 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003584 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003585 /* If rc should we check for EOPNOSUPP and
3586 disable the srvino flag? or in caller? */
3587 rc = -EIO; /* bad smb */
3588 else {
3589 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3590 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3591 struct file_chattr_info *pfinfo;
3592 /* BB Do we need a cast or hash here ? */
3593 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003594 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003595 rc = -EIO;
3596 goto GetExtAttrOut;
3597 }
3598 pfinfo = (struct file_chattr_info *)
3599 (data_offset + (char *) &pSMBr->hdr.Protocol);
3600 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003601 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003602 }
3603 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003604GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003605 cifs_buf_release(pSMB);
3606 if (rc == -EAGAIN)
3607 goto GetExtAttrRetry;
3608 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003609}
3610
Steve Frenchf654bac2005-04-28 22:41:04 -07003611#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
Jeff Layton79df1ba2010-12-06 12:52:08 -05003613#ifdef CONFIG_CIFS_ACL
3614/*
3615 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3616 * all NT TRANSACTS that we init here have total parm and data under about 400
3617 * bytes (to fit in small cifs buffer size), which is the case so far, it
3618 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3619 * returned setup area) and MaxParameterCount (returned parms size) must be set
3620 * by caller
3621 */
3622static int
3623smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003624 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003625 void **ret_buf)
3626{
3627 int rc;
3628 __u32 temp_offset;
3629 struct smb_com_ntransact_req *pSMB;
3630
3631 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3632 (void **)&pSMB);
3633 if (rc)
3634 return rc;
3635 *ret_buf = (void *)pSMB;
3636 pSMB->Reserved = 0;
3637 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3638 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003639 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003640 pSMB->ParameterCount = pSMB->TotalParameterCount;
3641 pSMB->DataCount = pSMB->TotalDataCount;
3642 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3643 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3644 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3645 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3646 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3647 pSMB->SubCommand = cpu_to_le16(sub_command);
3648 return 0;
3649}
3650
3651static int
3652validate_ntransact(char *buf, char **ppparm, char **ppdata,
3653 __u32 *pparmlen, __u32 *pdatalen)
3654{
3655 char *end_of_smb;
3656 __u32 data_count, data_offset, parm_count, parm_offset;
3657 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003658 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003659
3660 *pdatalen = 0;
3661 *pparmlen = 0;
3662
3663 if (buf == NULL)
3664 return -EINVAL;
3665
3666 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3667
Jeff Layton820a8032011-05-04 08:05:26 -04003668 bcc = get_bcc(&pSMBr->hdr);
3669 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003670 (char *)&pSMBr->ByteCount;
3671
3672 data_offset = le32_to_cpu(pSMBr->DataOffset);
3673 data_count = le32_to_cpu(pSMBr->DataCount);
3674 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3675 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3676
3677 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3678 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3679
3680 /* should we also check that parm and data areas do not overlap? */
3681 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003682 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003683 return -EINVAL;
3684 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003685 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003686 return -EINVAL;
3687 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003688 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003689 return -EINVAL;
3690 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003691 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3692 *ppdata, data_count, (data_count + *ppdata),
3693 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003694 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003695 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003696 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003697 return -EINVAL;
3698 }
3699 *pdatalen = data_count;
3700 *pparmlen = parm_count;
3701 return 0;
3702}
3703
Steve French0a4b92c2006-01-12 15:44:21 -08003704/* Get Security Descriptor (by handle) from remote server for a file or dir */
3705int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003706CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003707 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003708{
3709 int rc = 0;
3710 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003711 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003712 struct kvec iov[1];
3713
Joe Perchesf96637b2013-05-04 22:12:25 -05003714 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003715
Steve French630f3f0c2007-10-25 21:17:17 +00003716 *pbuflen = 0;
3717 *acl_inf = NULL;
3718
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003719 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003720 8 /* parm len */, tcon, (void **) &pSMB);
3721 if (rc)
3722 return rc;
3723
3724 pSMB->MaxParameterCount = cpu_to_le32(4);
3725 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3726 pSMB->MaxSetupCount = 0;
3727 pSMB->Fid = fid; /* file handle always le */
3728 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3729 CIFS_ACL_DACL);
3730 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003731 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003732 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003733 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003734
Steve Frencha761ac52007-10-18 21:45:27 +00003735 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003736 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003737 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003738 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003739 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003740 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003741 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003742 __u32 parm_len;
3743 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003744 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003745 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003746
3747/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003748 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003749 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003750 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003751 goto qsec_out;
3752 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3753
Joe Perchesf96637b2013-05-04 22:12:25 -05003754 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3755 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003756
3757 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3758 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003759 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003760 goto qsec_out;
3761 }
3762
3763/* BB check that data area is minimum length and as big as acl_len */
3764
Steve Frenchaf6f4612007-10-16 18:40:37 +00003765 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003766 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003767 cifs_dbg(VFS, "acl length %d does not match %d\n",
3768 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003769 if (*pbuflen > acl_len)
3770 *pbuflen = acl_len;
3771 }
Steve French0a4b92c2006-01-12 15:44:21 -08003772
Steve French630f3f0c2007-10-25 21:17:17 +00003773 /* check if buffer is big enough for the acl
3774 header followed by the smallest SID */
3775 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3776 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003777 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003778 rc = -EINVAL;
3779 *pbuflen = 0;
3780 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003781 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003782 if (*acl_inf == NULL) {
3783 *pbuflen = 0;
3784 rc = -ENOMEM;
3785 }
Steve French630f3f0c2007-10-25 21:17:17 +00003786 }
Steve French0a4b92c2006-01-12 15:44:21 -08003787 }
3788qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003789 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003790 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003791 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003792 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003793/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003794 return rc;
3795}
Steve French97837582007-12-31 07:47:21 +00003796
3797int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003798CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003799 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003800{
3801 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3802 int rc = 0;
3803 int bytes_returned = 0;
3804 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003805 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003806
3807setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003808 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003809 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003810 return rc;
Steve French97837582007-12-31 07:47:21 +00003811
3812 pSMB->MaxSetupCount = 0;
3813 pSMB->Reserved = 0;
3814
3815 param_count = 8;
3816 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3817 data_count = acllen;
3818 data_offset = param_offset + param_count;
3819 byte_count = 3 /* pad */ + param_count;
3820
3821 pSMB->DataCount = cpu_to_le32(data_count);
3822 pSMB->TotalDataCount = pSMB->DataCount;
3823 pSMB->MaxParameterCount = cpu_to_le32(4);
3824 pSMB->MaxDataCount = cpu_to_le32(16384);
3825 pSMB->ParameterCount = cpu_to_le32(param_count);
3826 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3827 pSMB->TotalParameterCount = pSMB->ParameterCount;
3828 pSMB->DataOffset = cpu_to_le32(data_offset);
3829 pSMB->SetupCount = 0;
3830 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3831 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3832
3833 pSMB->Fid = fid; /* file handle always le */
3834 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003835 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003836
3837 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003838 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3839 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003840 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003841 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003842 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003843
3844 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3845 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3846
Joe Perchesf96637b2013-05-04 22:12:25 -05003847 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3848 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003849 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003850 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003851 cifs_buf_release(pSMB);
3852
3853 if (rc == -EAGAIN)
3854 goto setCifsAclRetry;
3855
3856 return (rc);
3857}
3858
Jeff Layton79df1ba2010-12-06 12:52:08 -05003859#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003860
Steve French6b8edfe2005-08-23 20:26:03 -07003861/* Legacy Query Path Information call for lookup to old servers such
3862 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003863int
3864SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3865 const char *search_name, FILE_ALL_INFO *data,
3866 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003867{
Steve Frenchad7a2922008-02-07 23:25:02 +00003868 QUERY_INFORMATION_REQ *pSMB;
3869 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003870 int rc = 0;
3871 int bytes_returned;
3872 int name_len;
3873
Joe Perchesf96637b2013-05-04 22:12:25 -05003874 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003875QInfRetry:
3876 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003877 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003878 if (rc)
3879 return rc;
3880
3881 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3882 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003883 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003884 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003885 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003886 name_len++; /* trailing null */
3887 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003888 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003889 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003890 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003891 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003892 }
3893 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003894 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003895 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003896 pSMB->ByteCount = cpu_to_le16(name_len);
3897
3898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003900 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003901 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003902 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003903 struct timespec ts;
3904 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003905
3906 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003907 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003908 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003909 ts.tv_nsec = 0;
3910 ts.tv_sec = time;
3911 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003912 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3913 data->LastWriteTime = data->ChangeTime;
3914 data->LastAccessTime = 0;
3915 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003916 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003917 data->EndOfFile = data->AllocationSize;
3918 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003919 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003920 } else
3921 rc = -EIO; /* bad buffer passed in */
3922
3923 cifs_buf_release(pSMB);
3924
3925 if (rc == -EAGAIN)
3926 goto QInfRetry;
3927
3928 return rc;
3929}
3930
Jeff Laytonbcd53572010-02-12 07:44:16 -05003931int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003932CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003933 u16 netfid, FILE_ALL_INFO *pFindData)
3934{
3935 struct smb_t2_qfi_req *pSMB = NULL;
3936 struct smb_t2_qfi_rsp *pSMBr = NULL;
3937 int rc = 0;
3938 int bytes_returned;
3939 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003940
Jeff Laytonbcd53572010-02-12 07:44:16 -05003941QFileInfoRetry:
3942 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3943 (void **) &pSMBr);
3944 if (rc)
3945 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003946
Jeff Laytonbcd53572010-02-12 07:44:16 -05003947 params = 2 /* level */ + 2 /* fid */;
3948 pSMB->t2.TotalDataCount = 0;
3949 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3950 /* BB find exact max data count below from sess structure BB */
3951 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3952 pSMB->t2.MaxSetupCount = 0;
3953 pSMB->t2.Reserved = 0;
3954 pSMB->t2.Flags = 0;
3955 pSMB->t2.Timeout = 0;
3956 pSMB->t2.Reserved2 = 0;
3957 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3958 Fid) - 4);
3959 pSMB->t2.DataCount = 0;
3960 pSMB->t2.DataOffset = 0;
3961 pSMB->t2.SetupCount = 1;
3962 pSMB->t2.Reserved3 = 0;
3963 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3964 byte_count = params + 1 /* pad */ ;
3965 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3966 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3967 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3968 pSMB->Pad = 0;
3969 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003970 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003971
3972 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3973 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3974 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003975 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003976 } else { /* decode response */
3977 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3978
3979 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3980 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003981 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003982 rc = -EIO; /* bad smb */
3983 else if (pFindData) {
3984 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3985 memcpy((char *) pFindData,
3986 (char *) &pSMBr->hdr.Protocol +
3987 data_offset, sizeof(FILE_ALL_INFO));
3988 } else
3989 rc = -ENOMEM;
3990 }
3991 cifs_buf_release(pSMB);
3992 if (rc == -EAGAIN)
3993 goto QFileInfoRetry;
3994
3995 return rc;
3996}
Steve French6b8edfe2005-08-23 20:26:03 -07003997
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003999CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004000 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004001 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004002 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004004 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 TRANSACTION2_QPI_REQ *pSMB = NULL;
4006 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4007 int rc = 0;
4008 int bytes_returned;
4009 int name_len;
4010 __u16 params, byte_count;
4011
Joe Perchesf96637b2013-05-04 22:12:25 -05004012 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013QPathInfoRetry:
4014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4015 (void **) &pSMBr);
4016 if (rc)
4017 return rc;
4018
4019 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4020 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004021 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004022 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 name_len++; /* trailing null */
4024 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004025 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004026 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004028 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 }
4030
Steve French50c2f752007-07-13 00:33:32 +00004031 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 pSMB->TotalDataCount = 0;
4033 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004034 /* BB find exact max SMB PDU from sess structure BB */
4035 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 pSMB->MaxSetupCount = 0;
4037 pSMB->Reserved = 0;
4038 pSMB->Flags = 0;
4039 pSMB->Timeout = 0;
4040 pSMB->Reserved2 = 0;
4041 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004042 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 pSMB->DataCount = 0;
4044 pSMB->DataOffset = 0;
4045 pSMB->SetupCount = 1;
4046 pSMB->Reserved3 = 0;
4047 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4048 byte_count = params + 1 /* pad */ ;
4049 pSMB->TotalParameterCount = cpu_to_le16(params);
4050 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004051 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004052 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4053 else
4054 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004056 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 pSMB->ByteCount = cpu_to_le16(byte_count);
4058
4059 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4061 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004062 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 } else { /* decode response */
4064 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4065
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004066 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4067 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004068 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004070 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004071 rc = -EIO; /* 24 or 26 expected but we do not read
4072 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004074 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004076
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004077 /*
4078 * On legacy responses we do not read the last field,
4079 * EAsize, fortunately since it varies by subdialect and
4080 * also note it differs on Set vs Get, ie two bytes or 4
4081 * bytes depending but we don't care here.
4082 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004083 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004084 size = sizeof(FILE_INFO_STANDARD);
4085 else
4086 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004087 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004088 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 } else
4090 rc = -ENOMEM;
4091 }
4092 cifs_buf_release(pSMB);
4093 if (rc == -EAGAIN)
4094 goto QPathInfoRetry;
4095
4096 return rc;
4097}
4098
4099int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004100CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004101 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4102{
4103 struct smb_t2_qfi_req *pSMB = NULL;
4104 struct smb_t2_qfi_rsp *pSMBr = NULL;
4105 int rc = 0;
4106 int bytes_returned;
4107 __u16 params, byte_count;
4108
4109UnixQFileInfoRetry:
4110 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4111 (void **) &pSMBr);
4112 if (rc)
4113 return rc;
4114
4115 params = 2 /* level */ + 2 /* fid */;
4116 pSMB->t2.TotalDataCount = 0;
4117 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4118 /* BB find exact max data count below from sess structure BB */
4119 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4120 pSMB->t2.MaxSetupCount = 0;
4121 pSMB->t2.Reserved = 0;
4122 pSMB->t2.Flags = 0;
4123 pSMB->t2.Timeout = 0;
4124 pSMB->t2.Reserved2 = 0;
4125 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4126 Fid) - 4);
4127 pSMB->t2.DataCount = 0;
4128 pSMB->t2.DataOffset = 0;
4129 pSMB->t2.SetupCount = 1;
4130 pSMB->t2.Reserved3 = 0;
4131 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4132 byte_count = params + 1 /* pad */ ;
4133 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4134 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4135 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4136 pSMB->Pad = 0;
4137 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004138 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004139
4140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4142 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004143 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004144 } else { /* decode response */
4145 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4146
Jeff Layton820a8032011-05-04 08:05:26 -04004147 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004148 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 -05004149 rc = -EIO; /* bad smb */
4150 } else {
4151 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4152 memcpy((char *) pFindData,
4153 (char *) &pSMBr->hdr.Protocol +
4154 data_offset,
4155 sizeof(FILE_UNIX_BASIC_INFO));
4156 }
4157 }
4158
4159 cifs_buf_release(pSMB);
4160 if (rc == -EAGAIN)
4161 goto UnixQFileInfoRetry;
4162
4163 return rc;
4164}
4165
4166int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004167CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004169 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004170 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171{
4172/* SMB_QUERY_FILE_UNIX_BASIC */
4173 TRANSACTION2_QPI_REQ *pSMB = NULL;
4174 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4175 int rc = 0;
4176 int bytes_returned = 0;
4177 int name_len;
4178 __u16 params, byte_count;
4179
Joe Perchesf96637b2013-05-04 22:12:25 -05004180 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181UnixQPathInfoRetry:
4182 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4183 (void **) &pSMBr);
4184 if (rc)
4185 return rc;
4186
4187 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4188 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004189 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4190 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 name_len++; /* trailing null */
4192 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004193 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 name_len = strnlen(searchName, PATH_MAX);
4195 name_len++; /* trailing null */
4196 strncpy(pSMB->FileName, searchName, name_len);
4197 }
4198
Steve French50c2f752007-07-13 00:33:32 +00004199 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 pSMB->TotalDataCount = 0;
4201 pSMB->MaxParameterCount = cpu_to_le16(2);
4202 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004203 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 pSMB->MaxSetupCount = 0;
4205 pSMB->Reserved = 0;
4206 pSMB->Flags = 0;
4207 pSMB->Timeout = 0;
4208 pSMB->Reserved2 = 0;
4209 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004210 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 pSMB->DataCount = 0;
4212 pSMB->DataOffset = 0;
4213 pSMB->SetupCount = 1;
4214 pSMB->Reserved3 = 0;
4215 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4216 byte_count = params + 1 /* pad */ ;
4217 pSMB->TotalParameterCount = cpu_to_le16(params);
4218 pSMB->ParameterCount = pSMB->TotalParameterCount;
4219 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4220 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004221 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 pSMB->ByteCount = cpu_to_le16(byte_count);
4223
4224 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4225 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4226 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004227 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 } else { /* decode response */
4229 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4230
Jeff Layton820a8032011-05-04 08:05:26 -04004231 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004232 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 -07004233 rc = -EIO; /* bad smb */
4234 } else {
4235 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4236 memcpy((char *) pFindData,
4237 (char *) &pSMBr->hdr.Protocol +
4238 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004239 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 }
4241 }
4242 cifs_buf_release(pSMB);
4243 if (rc == -EAGAIN)
4244 goto UnixQPathInfoRetry;
4245
4246 return rc;
4247}
4248
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249/* xid, tcon, searchName and codepage are input parms, rest are returned */
4250int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004251CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004252 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004253 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004254 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255{
4256/* level 257 SMB_ */
4257 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4258 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004259 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 int rc = 0;
4261 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004262 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004264 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
Joe Perchesf96637b2013-05-04 22:12:25 -05004266 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267
4268findFirstRetry:
4269 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4270 (void **) &pSMBr);
4271 if (rc)
4272 return rc;
4273
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004274 nls_codepage = cifs_sb->local_nls;
4275 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4276
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4278 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004279 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4280 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004281 /* We can not add the asterik earlier in case
4282 it got remapped to 0xF03A as if it were part of the
4283 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004285 if (msearch) {
4286 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4287 pSMB->FileName[name_len+1] = 0;
4288 pSMB->FileName[name_len+2] = '*';
4289 pSMB->FileName[name_len+3] = 0;
4290 name_len += 4; /* now the trailing null */
4291 /* null terminate just in case */
4292 pSMB->FileName[name_len] = 0;
4293 pSMB->FileName[name_len+1] = 0;
4294 name_len += 2;
4295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 } else { /* BB add check for overrun of SMB buf BB */
4297 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004299 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 free buffer exit; BB */
4301 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004302 if (msearch) {
4303 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4304 pSMB->FileName[name_len+1] = '*';
4305 pSMB->FileName[name_len+2] = 0;
4306 name_len += 3;
4307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 }
4309
4310 params = 12 + name_len /* includes null */ ;
4311 pSMB->TotalDataCount = 0; /* no EAs */
4312 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004313 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 pSMB->MaxSetupCount = 0;
4315 pSMB->Reserved = 0;
4316 pSMB->Flags = 0;
4317 pSMB->Timeout = 0;
4318 pSMB->Reserved2 = 0;
4319 byte_count = params + 1 /* pad */ ;
4320 pSMB->TotalParameterCount = cpu_to_le16(params);
4321 pSMB->ParameterCount = pSMB->TotalParameterCount;
4322 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004323 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4324 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 pSMB->DataCount = 0;
4326 pSMB->DataOffset = 0;
4327 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4328 pSMB->Reserved3 = 0;
4329 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4330 pSMB->SearchAttributes =
4331 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4332 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004333 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004334 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4336
4337 /* BB what should we set StorageType to? Does it matter? BB */
4338 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004339 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 pSMB->ByteCount = cpu_to_le16(byte_count);
4341
4342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004344 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345
Steve French88274812006-03-09 22:21:45 +00004346 if (rc) {/* BB add logic to retry regular search if Unix search
4347 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004349 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004350
Steve French88274812006-03-09 22:21:45 +00004351 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
4353 /* BB eventually could optimize out free and realloc of buf */
4354 /* for this case */
4355 if (rc == -EAGAIN)
4356 goto findFirstRetry;
4357 } else { /* decode response */
4358 /* BB remember to free buffer if error BB */
4359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004360 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004361 unsigned int lnoff;
4362
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004364 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 else
Steve French4b18f2a2008-04-29 00:06:05 +00004366 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
4368 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004369 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004370 psrch_inf->srch_entries_start =
4371 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4374 le16_to_cpu(pSMBr->t2.ParameterOffset));
4375
Steve French790fe572007-07-07 19:25:05 +00004376 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004377 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 else
Steve French4b18f2a2008-04-29 00:06:05 +00004379 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
Steve French50c2f752007-07-13 00:33:32 +00004381 psrch_inf->entries_in_buffer =
4382 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004383 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004385 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004386 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004387 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004388 psrch_inf->last_entry = NULL;
4389 return rc;
4390 }
4391
Steve French0752f152008-10-07 20:03:33 +00004392 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004393 lnoff;
4394
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004395 if (pnetfid)
4396 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 } else {
4398 cifs_buf_release(pSMB);
4399 }
4400 }
4401
4402 return rc;
4403}
4404
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004405int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4406 __u16 searchHandle, __u16 search_flags,
4407 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408{
4409 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4410 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004411 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 char *response_data;
4413 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004414 int bytes_returned;
4415 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 __u16 params, byte_count;
4417
Joe Perchesf96637b2013-05-04 22:12:25 -05004418 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
Steve French4b18f2a2008-04-29 00:06:05 +00004420 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 return -ENOENT;
4422
4423 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4424 (void **) &pSMBr);
4425 if (rc)
4426 return rc;
4427
Steve French50c2f752007-07-13 00:33:32 +00004428 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 byte_count = 0;
4430 pSMB->TotalDataCount = 0; /* no EAs */
4431 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004432 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 pSMB->MaxSetupCount = 0;
4434 pSMB->Reserved = 0;
4435 pSMB->Flags = 0;
4436 pSMB->Timeout = 0;
4437 pSMB->Reserved2 = 0;
4438 pSMB->ParameterOffset = cpu_to_le16(
4439 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4440 pSMB->DataCount = 0;
4441 pSMB->DataOffset = 0;
4442 pSMB->SetupCount = 1;
4443 pSMB->Reserved3 = 0;
4444 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4445 pSMB->SearchHandle = searchHandle; /* always kept as le */
4446 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004447 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4449 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004450 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451
4452 name_len = psrch_inf->resume_name_len;
4453 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004454 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4456 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004457 /* 14 byte parm len above enough for 2 byte null terminator */
4458 pSMB->ResumeFileName[name_len] = 0;
4459 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 } else {
4461 rc = -EINVAL;
4462 goto FNext2_err_exit;
4463 }
4464 byte_count = params + 1 /* pad */ ;
4465 pSMB->TotalParameterCount = cpu_to_le16(params);
4466 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004467 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004469
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004472 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 if (rc) {
4474 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004475 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004476 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004477 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004479 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 } else { /* decode response */
4481 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004482
Steve French790fe572007-07-07 19:25:05 +00004483 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004484 unsigned int lnoff;
4485
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 /* BB fixme add lock for file (srch_info) struct here */
4487 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004488 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 else
Steve French4b18f2a2008-04-29 00:06:05 +00004490 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 response_data = (char *) &pSMBr->hdr.Protocol +
4492 le16_to_cpu(pSMBr->t2.ParameterOffset);
4493 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4494 response_data = (char *)&pSMBr->hdr.Protocol +
4495 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004496 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004497 cifs_small_buf_release(
4498 psrch_inf->ntwrk_buf_start);
4499 else
4500 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 psrch_inf->srch_entries_start = response_data;
4502 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004503 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004504 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004505 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 else
Steve French4b18f2a2008-04-29 00:06:05 +00004507 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004508 psrch_inf->entries_in_buffer =
4509 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 psrch_inf->index_of_last_entry +=
4511 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004512 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004513 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004514 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004515 psrch_inf->last_entry = NULL;
4516 return rc;
4517 } else
4518 psrch_inf->last_entry =
4519 psrch_inf->srch_entries_start + lnoff;
4520
Joe Perchesf96637b2013-05-04 22:12:25 -05004521/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4522 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523
4524 /* BB fixme add unlock here */
4525 }
4526
4527 }
4528
4529 /* BB On error, should we leave previous search buf (and count and
4530 last entry fields) intact or free the previous one? */
4531
4532 /* Note: On -EAGAIN error only caller can retry on handle based calls
4533 since file handle passed in no longer valid */
4534FNext2_err_exit:
4535 if (rc != 0)
4536 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 return rc;
4538}
4539
4540int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004541CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004542 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543{
4544 int rc = 0;
4545 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546
Joe Perchesf96637b2013-05-04 22:12:25 -05004547 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4549
4550 /* no sense returning error if session restarted
4551 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004552 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 return 0;
4554 if (rc)
4555 return rc;
4556
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 pSMB->FileID = searchHandle;
4558 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004559 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004560 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004561 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004562
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004563 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
4565 /* Since session is dead, search handle closed on server already */
4566 if (rc == -EAGAIN)
4567 rc = 0;
4568
4569 return rc;
4570}
4571
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004573CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004574 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004575 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576{
4577 int rc = 0;
4578 TRANSACTION2_QPI_REQ *pSMB = NULL;
4579 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4580 int name_len, bytes_returned;
4581 __u16 params, byte_count;
4582
Joe Perchesf96637b2013-05-04 22:12:25 -05004583 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004584 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004585 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
4587GetInodeNumberRetry:
4588 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004589 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 if (rc)
4591 return rc;
4592
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4594 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004595 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004596 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004597 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 name_len++; /* trailing null */
4599 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004600 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004601 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004603 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 }
4605
4606 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4607 pSMB->TotalDataCount = 0;
4608 pSMB->MaxParameterCount = cpu_to_le16(2);
4609 /* BB find exact max data count below from sess structure BB */
4610 pSMB->MaxDataCount = cpu_to_le16(4000);
4611 pSMB->MaxSetupCount = 0;
4612 pSMB->Reserved = 0;
4613 pSMB->Flags = 0;
4614 pSMB->Timeout = 0;
4615 pSMB->Reserved2 = 0;
4616 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004617 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 pSMB->DataCount = 0;
4619 pSMB->DataOffset = 0;
4620 pSMB->SetupCount = 1;
4621 pSMB->Reserved3 = 0;
4622 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4623 byte_count = params + 1 /* pad */ ;
4624 pSMB->TotalParameterCount = cpu_to_le16(params);
4625 pSMB->ParameterCount = pSMB->TotalParameterCount;
4626 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4627 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004628 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 pSMB->ByteCount = cpu_to_le16(byte_count);
4630
4631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4633 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004634 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 } else {
4636 /* decode response */
4637 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004639 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 /* If rc should we check for EOPNOSUPP and
4641 disable the srvino flag? or in caller? */
4642 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004643 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4645 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004646 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004648 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004649 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 rc = -EIO;
4651 goto GetInodeNumOut;
4652 }
4653 pfinfo = (struct file_internal_info *)
4654 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004655 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 }
4657 }
4658GetInodeNumOut:
4659 cifs_buf_release(pSMB);
4660 if (rc == -EAGAIN)
4661 goto GetInodeNumberRetry;
4662 return rc;
4663}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664
Igor Mammedovfec45852008-05-16 13:06:30 +04004665/* parses DFS refferal V3 structure
4666 * caller is responsible for freeing target_nodes
4667 * returns:
4668 * on success - 0
4669 * on failure - errno
4670 */
4671static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004672parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004673 unsigned int *num_of_nodes,
4674 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004675 const struct nls_table *nls_codepage, int remap,
4676 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004677{
4678 int i, rc = 0;
4679 char *data_end;
4680 bool is_unicode;
4681 struct dfs_referral_level_3 *ref;
4682
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004683 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4684 is_unicode = true;
4685 else
4686 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004687 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4688
4689 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004690 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4691 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004692 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004693 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004694 }
4695
4696 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004697 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004698 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4699 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004700 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004701 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004702 }
4703
4704 /* get the upper boundary of the resp buffer */
4705 data_end = (char *)(&(pSMBr->PathConsumed)) +
4706 le16_to_cpu(pSMBr->t2.DataCount);
4707
Joe Perchesf96637b2013-05-04 22:12:25 -05004708 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4709 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004710
Joe Perchesf96637b2013-05-04 22:12:25 -05004711 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4712 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004713 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004714 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004715 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004716 }
4717
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004718 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004719 for (i = 0; i < *num_of_nodes; i++) {
4720 char *temp;
4721 int max_len;
4722 struct dfs_info3_param *node = (*target_nodes)+i;
4723
Steve French0e0d2cf2009-05-01 05:27:32 +00004724 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004725 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004726 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4727 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004728 if (tmp == NULL) {
4729 rc = -ENOMEM;
4730 goto parse_DFS_referrals_exit;
4731 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004732 cifsConvertToUTF16((__le16 *) tmp, searchName,
4733 PATH_MAX, nls_codepage, remap);
4734 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004735 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004736 nls_codepage);
4737 kfree(tmp);
4738 } else
4739 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4740
Igor Mammedovfec45852008-05-16 13:06:30 +04004741 node->server_type = le16_to_cpu(ref->ServerType);
4742 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4743
4744 /* copy DfsPath */
4745 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4746 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004747 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4748 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004749 if (!node->path_name) {
4750 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004751 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004752 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004753
4754 /* copy link target UNC */
4755 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4756 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004757 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4758 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004759 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004760 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004761 goto parse_DFS_referrals_exit;
4762 }
4763
4764 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004765 }
4766
Steve Frencha1fe78f2008-05-16 18:48:38 +00004767parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004768 if (rc) {
4769 free_dfs_info_array(*target_nodes, *num_of_nodes);
4770 *target_nodes = NULL;
4771 *num_of_nodes = 0;
4772 }
4773 return rc;
4774}
4775
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004777CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004778 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004779 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004780 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781{
4782/* TRANS2_GET_DFS_REFERRAL */
4783 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4784 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 int rc = 0;
4786 int bytes_returned;
4787 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004789 *num_of_nodes = 0;
4790 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791
Joe Perchesf96637b2013-05-04 22:12:25 -05004792 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 if (ses == NULL)
4794 return -ENODEV;
4795getDFSRetry:
4796 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4797 (void **) &pSMBr);
4798 if (rc)
4799 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004800
4801 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004802 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004803 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 pSMB->hdr.Tid = ses->ipc_tid;
4805 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004806 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004808 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
4811 if (ses->capabilities & CAP_UNICODE) {
4812 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4813 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004814 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004815 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004816 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 name_len++; /* trailing null */
4818 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004819 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004820 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004822 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 }
4824
Steve French790fe572007-07-07 19:25:05 +00004825 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004826 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004827 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4828 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4829 }
4830
Steve French50c2f752007-07-13 00:33:32 +00004831 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004832
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 params = 2 /* level */ + name_len /*includes null */ ;
4834 pSMB->TotalDataCount = 0;
4835 pSMB->DataCount = 0;
4836 pSMB->DataOffset = 0;
4837 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004838 /* BB find exact max SMB PDU from sess structure BB */
4839 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 pSMB->MaxSetupCount = 0;
4841 pSMB->Reserved = 0;
4842 pSMB->Flags = 0;
4843 pSMB->Timeout = 0;
4844 pSMB->Reserved2 = 0;
4845 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004846 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 pSMB->SetupCount = 1;
4848 pSMB->Reserved3 = 0;
4849 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4850 byte_count = params + 3 /* pad */ ;
4851 pSMB->ParameterCount = cpu_to_le16(params);
4852 pSMB->TotalParameterCount = pSMB->ParameterCount;
4853 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004854 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 pSMB->ByteCount = cpu_to_le16(byte_count);
4856
4857 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4859 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004860 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004861 goto GetDFSRefExit;
4862 }
4863 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004865 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004866 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004867 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004868 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004870
Joe Perchesf96637b2013-05-04 22:12:25 -05004871 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4872 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004873
4874 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004875 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004876 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004877 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004878
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004880 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881
4882 if (rc == -EAGAIN)
4883 goto getDFSRetry;
4884
4885 return rc;
4886}
4887
Steve French20962432005-09-21 22:05:57 -07004888/* Query File System Info such as free space to old servers such as Win 9x */
4889int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004890SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4891 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004892{
4893/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4894 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4895 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4896 FILE_SYSTEM_ALLOC_INFO *response_data;
4897 int rc = 0;
4898 int bytes_returned = 0;
4899 __u16 params, byte_count;
4900
Joe Perchesf96637b2013-05-04 22:12:25 -05004901 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004902oldQFSInfoRetry:
4903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4904 (void **) &pSMBr);
4905 if (rc)
4906 return rc;
Steve French20962432005-09-21 22:05:57 -07004907
4908 params = 2; /* level */
4909 pSMB->TotalDataCount = 0;
4910 pSMB->MaxParameterCount = cpu_to_le16(2);
4911 pSMB->MaxDataCount = cpu_to_le16(1000);
4912 pSMB->MaxSetupCount = 0;
4913 pSMB->Reserved = 0;
4914 pSMB->Flags = 0;
4915 pSMB->Timeout = 0;
4916 pSMB->Reserved2 = 0;
4917 byte_count = params + 1 /* pad */ ;
4918 pSMB->TotalParameterCount = cpu_to_le16(params);
4919 pSMB->ParameterCount = pSMB->TotalParameterCount;
4920 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4921 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4922 pSMB->DataCount = 0;
4923 pSMB->DataOffset = 0;
4924 pSMB->SetupCount = 1;
4925 pSMB->Reserved3 = 0;
4926 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4927 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004928 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004929 pSMB->ByteCount = cpu_to_le16(byte_count);
4930
4931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4933 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004934 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004935 } else { /* decode response */
4936 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4937
Jeff Layton820a8032011-05-04 08:05:26 -04004938 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004939 rc = -EIO; /* bad smb */
4940 else {
4941 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004942 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004943 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004944
Steve French50c2f752007-07-13 00:33:32 +00004945 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004946 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4947 FSData->f_bsize =
4948 le16_to_cpu(response_data->BytesPerSector) *
4949 le32_to_cpu(response_data->
4950 SectorsPerAllocationUnit);
4951 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004952 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004953 FSData->f_bfree = FSData->f_bavail =
4954 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004955 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4956 (unsigned long long)FSData->f_blocks,
4957 (unsigned long long)FSData->f_bfree,
4958 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004959 }
4960 }
4961 cifs_buf_release(pSMB);
4962
4963 if (rc == -EAGAIN)
4964 goto oldQFSInfoRetry;
4965
4966 return rc;
4967}
4968
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004970CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4971 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972{
4973/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4974 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4975 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4976 FILE_SYSTEM_INFO *response_data;
4977 int rc = 0;
4978 int bytes_returned = 0;
4979 __u16 params, byte_count;
4980
Joe Perchesf96637b2013-05-04 22:12:25 -05004981 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982QFSInfoRetry:
4983 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4984 (void **) &pSMBr);
4985 if (rc)
4986 return rc;
4987
4988 params = 2; /* level */
4989 pSMB->TotalDataCount = 0;
4990 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004991 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 pSMB->MaxSetupCount = 0;
4993 pSMB->Reserved = 0;
4994 pSMB->Flags = 0;
4995 pSMB->Timeout = 0;
4996 pSMB->Reserved2 = 0;
4997 byte_count = params + 1 /* pad */ ;
4998 pSMB->TotalParameterCount = cpu_to_le16(params);
4999 pSMB->ParameterCount = pSMB->TotalParameterCount;
5000 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005001 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 pSMB->DataCount = 0;
5003 pSMB->DataOffset = 0;
5004 pSMB->SetupCount = 1;
5005 pSMB->Reserved3 = 0;
5006 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5007 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005008 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 pSMB->ByteCount = cpu_to_le16(byte_count);
5010
5011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5013 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005014 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005016 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
Jeff Layton820a8032011-05-04 08:05:26 -04005018 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 rc = -EIO; /* bad smb */
5020 else {
5021 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022
5023 response_data =
5024 (FILE_SYSTEM_INFO
5025 *) (((char *) &pSMBr->hdr.Protocol) +
5026 data_offset);
5027 FSData->f_bsize =
5028 le32_to_cpu(response_data->BytesPerSector) *
5029 le32_to_cpu(response_data->
5030 SectorsPerAllocationUnit);
5031 FSData->f_blocks =
5032 le64_to_cpu(response_data->TotalAllocationUnits);
5033 FSData->f_bfree = FSData->f_bavail =
5034 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005035 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5036 (unsigned long long)FSData->f_blocks,
5037 (unsigned long long)FSData->f_bfree,
5038 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 }
5040 }
5041 cifs_buf_release(pSMB);
5042
5043 if (rc == -EAGAIN)
5044 goto QFSInfoRetry;
5045
5046 return rc;
5047}
5048
5049int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005050CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051{
5052/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5053 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5054 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5055 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5056 int rc = 0;
5057 int bytes_returned = 0;
5058 __u16 params, byte_count;
5059
Joe Perchesf96637b2013-05-04 22:12:25 -05005060 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061QFSAttributeRetry:
5062 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5063 (void **) &pSMBr);
5064 if (rc)
5065 return rc;
5066
5067 params = 2; /* level */
5068 pSMB->TotalDataCount = 0;
5069 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005070 /* BB find exact max SMB PDU from sess structure BB */
5071 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 pSMB->MaxSetupCount = 0;
5073 pSMB->Reserved = 0;
5074 pSMB->Flags = 0;
5075 pSMB->Timeout = 0;
5076 pSMB->Reserved2 = 0;
5077 byte_count = params + 1 /* pad */ ;
5078 pSMB->TotalParameterCount = cpu_to_le16(params);
5079 pSMB->ParameterCount = pSMB->TotalParameterCount;
5080 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005081 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 pSMB->DataCount = 0;
5083 pSMB->DataOffset = 0;
5084 pSMB->SetupCount = 1;
5085 pSMB->Reserved3 = 0;
5086 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5087 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005088 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 pSMB->ByteCount = cpu_to_le16(byte_count);
5090
5091 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5092 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5093 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005094 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 } else { /* decode response */
5096 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5097
Jeff Layton820a8032011-05-04 08:05:26 -04005098 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005099 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 rc = -EIO; /* bad smb */
5101 } else {
5102 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5103 response_data =
5104 (FILE_SYSTEM_ATTRIBUTE_INFO
5105 *) (((char *) &pSMBr->hdr.Protocol) +
5106 data_offset);
5107 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005108 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 }
5110 }
5111 cifs_buf_release(pSMB);
5112
5113 if (rc == -EAGAIN)
5114 goto QFSAttributeRetry;
5115
5116 return rc;
5117}
5118
5119int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005120CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121{
5122/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5123 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5124 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5125 FILE_SYSTEM_DEVICE_INFO *response_data;
5126 int rc = 0;
5127 int bytes_returned = 0;
5128 __u16 params, byte_count;
5129
Joe Perchesf96637b2013-05-04 22:12:25 -05005130 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131QFSDeviceRetry:
5132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5133 (void **) &pSMBr);
5134 if (rc)
5135 return rc;
5136
5137 params = 2; /* level */
5138 pSMB->TotalDataCount = 0;
5139 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005140 /* BB find exact max SMB PDU from sess structure BB */
5141 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 pSMB->MaxSetupCount = 0;
5143 pSMB->Reserved = 0;
5144 pSMB->Flags = 0;
5145 pSMB->Timeout = 0;
5146 pSMB->Reserved2 = 0;
5147 byte_count = params + 1 /* pad */ ;
5148 pSMB->TotalParameterCount = cpu_to_le16(params);
5149 pSMB->ParameterCount = pSMB->TotalParameterCount;
5150 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005151 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152
5153 pSMB->DataCount = 0;
5154 pSMB->DataOffset = 0;
5155 pSMB->SetupCount = 1;
5156 pSMB->Reserved3 = 0;
5157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5158 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005159 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 pSMB->ByteCount = cpu_to_le16(byte_count);
5161
5162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5164 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005165 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 } else { /* decode response */
5167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5168
Jeff Layton820a8032011-05-04 08:05:26 -04005169 if (rc || get_bcc(&pSMBr->hdr) <
5170 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 rc = -EIO; /* bad smb */
5172 else {
5173 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5174 response_data =
Steve French737b7582005-04-28 22:41:06 -07005175 (FILE_SYSTEM_DEVICE_INFO *)
5176 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 data_offset);
5178 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005179 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 }
5181 }
5182 cifs_buf_release(pSMB);
5183
5184 if (rc == -EAGAIN)
5185 goto QFSDeviceRetry;
5186
5187 return rc;
5188}
5189
5190int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005191CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192{
5193/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5194 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5195 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5196 FILE_SYSTEM_UNIX_INFO *response_data;
5197 int rc = 0;
5198 int bytes_returned = 0;
5199 __u16 params, byte_count;
5200
Joe Perchesf96637b2013-05-04 22:12:25 -05005201 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005203 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5204 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 if (rc)
5206 return rc;
5207
5208 params = 2; /* level */
5209 pSMB->TotalDataCount = 0;
5210 pSMB->DataCount = 0;
5211 pSMB->DataOffset = 0;
5212 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005213 /* BB find exact max SMB PDU from sess structure BB */
5214 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 pSMB->MaxSetupCount = 0;
5216 pSMB->Reserved = 0;
5217 pSMB->Flags = 0;
5218 pSMB->Timeout = 0;
5219 pSMB->Reserved2 = 0;
5220 byte_count = params + 1 /* pad */ ;
5221 pSMB->ParameterCount = cpu_to_le16(params);
5222 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005223 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5224 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 pSMB->SetupCount = 1;
5226 pSMB->Reserved3 = 0;
5227 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5228 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005229 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 pSMB->ByteCount = cpu_to_le16(byte_count);
5231
5232 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5233 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5234 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005235 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 } else { /* decode response */
5237 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5238
Jeff Layton820a8032011-05-04 08:05:26 -04005239 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 rc = -EIO; /* bad smb */
5241 } else {
5242 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5243 response_data =
5244 (FILE_SYSTEM_UNIX_INFO
5245 *) (((char *) &pSMBr->hdr.Protocol) +
5246 data_offset);
5247 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005248 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 }
5250 }
5251 cifs_buf_release(pSMB);
5252
5253 if (rc == -EAGAIN)
5254 goto QFSUnixRetry;
5255
5256
5257 return rc;
5258}
5259
Jeremy Allisonac670552005-06-22 17:26:35 -07005260int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005261CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005262{
5263/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5264 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5265 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5266 int rc = 0;
5267 int bytes_returned = 0;
5268 __u16 params, param_offset, offset, byte_count;
5269
Joe Perchesf96637b2013-05-04 22:12:25 -05005270 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005271SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005272 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005273 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5274 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005275 if (rc)
5276 return rc;
5277
5278 params = 4; /* 2 bytes zero followed by info level. */
5279 pSMB->MaxSetupCount = 0;
5280 pSMB->Reserved = 0;
5281 pSMB->Flags = 0;
5282 pSMB->Timeout = 0;
5283 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005284 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5285 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005286 offset = param_offset + params;
5287
5288 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005289 /* BB find exact max SMB PDU from sess structure BB */
5290 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005291 pSMB->SetupCount = 1;
5292 pSMB->Reserved3 = 0;
5293 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5294 byte_count = 1 /* pad */ + params + 12;
5295
5296 pSMB->DataCount = cpu_to_le16(12);
5297 pSMB->ParameterCount = cpu_to_le16(params);
5298 pSMB->TotalDataCount = pSMB->DataCount;
5299 pSMB->TotalParameterCount = pSMB->ParameterCount;
5300 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5301 pSMB->DataOffset = cpu_to_le16(offset);
5302
5303 /* Params. */
5304 pSMB->FileNum = 0;
5305 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5306
5307 /* Data. */
5308 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5309 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5310 pSMB->ClientUnixCap = cpu_to_le64(cap);
5311
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005312 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005313 pSMB->ByteCount = cpu_to_le16(byte_count);
5314
5315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5317 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005318 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005319 } else { /* decode response */
5320 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005321 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005322 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005323 }
5324 cifs_buf_release(pSMB);
5325
5326 if (rc == -EAGAIN)
5327 goto SETFSUnixRetry;
5328
5329 return rc;
5330}
5331
5332
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333
5334int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005335CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005336 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337{
5338/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5339 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5340 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5341 FILE_SYSTEM_POSIX_INFO *response_data;
5342 int rc = 0;
5343 int bytes_returned = 0;
5344 __u16 params, byte_count;
5345
Joe Perchesf96637b2013-05-04 22:12:25 -05005346 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347QFSPosixRetry:
5348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5349 (void **) &pSMBr);
5350 if (rc)
5351 return rc;
5352
5353 params = 2; /* level */
5354 pSMB->TotalDataCount = 0;
5355 pSMB->DataCount = 0;
5356 pSMB->DataOffset = 0;
5357 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005358 /* BB find exact max SMB PDU from sess structure BB */
5359 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 pSMB->MaxSetupCount = 0;
5361 pSMB->Reserved = 0;
5362 pSMB->Flags = 0;
5363 pSMB->Timeout = 0;
5364 pSMB->Reserved2 = 0;
5365 byte_count = params + 1 /* pad */ ;
5366 pSMB->ParameterCount = cpu_to_le16(params);
5367 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005368 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5369 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 pSMB->SetupCount = 1;
5371 pSMB->Reserved3 = 0;
5372 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5373 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005374 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 pSMB->ByteCount = cpu_to_le16(byte_count);
5376
5377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5378 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5379 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005380 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 } else { /* decode response */
5382 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5383
Jeff Layton820a8032011-05-04 08:05:26 -04005384 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 rc = -EIO; /* bad smb */
5386 } else {
5387 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5388 response_data =
5389 (FILE_SYSTEM_POSIX_INFO
5390 *) (((char *) &pSMBr->hdr.Protocol) +
5391 data_offset);
5392 FSData->f_bsize =
5393 le32_to_cpu(response_data->BlockSize);
5394 FSData->f_blocks =
5395 le64_to_cpu(response_data->TotalBlocks);
5396 FSData->f_bfree =
5397 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005398 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 FSData->f_bavail = FSData->f_bfree;
5400 } else {
5401 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005402 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 }
Steve French790fe572007-07-07 19:25:05 +00005404 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005406 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005407 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005409 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 }
5411 }
5412 cifs_buf_release(pSMB);
5413
5414 if (rc == -EAGAIN)
5415 goto QFSPosixRetry;
5416
5417 return rc;
5418}
5419
5420
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005421/*
5422 * We can not use write of zero bytes trick to set file size due to need for
5423 * large file support. Also note that this SetPathInfo is preferred to
5424 * SetFileInfo based method in next routine which is only needed to work around
5425 * a sharing violation bugin Samba which this routine can run into.
5426 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005428CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005429 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5430 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431{
5432 struct smb_com_transaction2_spi_req *pSMB = NULL;
5433 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5434 struct file_end_of_file_info *parm_data;
5435 int name_len;
5436 int rc = 0;
5437 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005438 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5439
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 __u16 params, byte_count, data_count, param_offset, offset;
5441
Joe Perchesf96637b2013-05-04 22:12:25 -05005442 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443SetEOFRetry:
5444 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5445 (void **) &pSMBr);
5446 if (rc)
5447 return rc;
5448
5449 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5450 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005451 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5452 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 name_len++; /* trailing null */
5454 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005455 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005456 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005458 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 }
5460 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005461 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005463 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 pSMB->MaxSetupCount = 0;
5465 pSMB->Reserved = 0;
5466 pSMB->Flags = 0;
5467 pSMB->Timeout = 0;
5468 pSMB->Reserved2 = 0;
5469 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005470 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005472 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005473 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5474 pSMB->InformationLevel =
5475 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5476 else
5477 pSMB->InformationLevel =
5478 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5479 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5481 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005482 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 else
5484 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005485 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 }
5487
5488 parm_data =
5489 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5490 offset);
5491 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5492 pSMB->DataOffset = cpu_to_le16(offset);
5493 pSMB->SetupCount = 1;
5494 pSMB->Reserved3 = 0;
5495 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5496 byte_count = 3 /* pad */ + params + data_count;
5497 pSMB->DataCount = cpu_to_le16(data_count);
5498 pSMB->TotalDataCount = pSMB->DataCount;
5499 pSMB->ParameterCount = cpu_to_le16(params);
5500 pSMB->TotalParameterCount = pSMB->ParameterCount;
5501 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005502 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 parm_data->FileSize = cpu_to_le64(size);
5504 pSMB->ByteCount = cpu_to_le16(byte_count);
5505 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5506 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005507 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005508 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
5510 cifs_buf_release(pSMB);
5511
5512 if (rc == -EAGAIN)
5513 goto SetEOFRetry;
5514
5515 return rc;
5516}
5517
5518int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005519CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5520 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521{
5522 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 struct file_end_of_file_info *parm_data;
5524 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 __u16 params, param_offset, offset, byte_count, count;
5526
Joe Perchesf96637b2013-05-04 22:12:25 -05005527 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5528 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005529 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5530
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 if (rc)
5532 return rc;
5533
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005534 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5535 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005536
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 params = 6;
5538 pSMB->MaxSetupCount = 0;
5539 pSMB->Reserved = 0;
5540 pSMB->Flags = 0;
5541 pSMB->Timeout = 0;
5542 pSMB->Reserved2 = 0;
5543 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5544 offset = param_offset + params;
5545
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 count = sizeof(struct file_end_of_file_info);
5547 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005548 /* BB find exact max SMB PDU from sess structure BB */
5549 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 pSMB->SetupCount = 1;
5551 pSMB->Reserved3 = 0;
5552 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5553 byte_count = 3 /* pad */ + params + count;
5554 pSMB->DataCount = cpu_to_le16(count);
5555 pSMB->ParameterCount = cpu_to_le16(params);
5556 pSMB->TotalDataCount = pSMB->DataCount;
5557 pSMB->TotalParameterCount = pSMB->ParameterCount;
5558 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5559 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005560 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5561 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 pSMB->DataOffset = cpu_to_le16(offset);
5563 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005564 pSMB->Fid = cfile->fid.netfid;
5565 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5567 pSMB->InformationLevel =
5568 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5569 else
5570 pSMB->InformationLevel =
5571 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005572 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5574 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005575 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 else
5577 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005578 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 }
5580 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005581 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005583 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005585 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5586 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 }
5588
Steve French50c2f752007-07-13 00:33:32 +00005589 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 since file handle passed in no longer valid */
5591
5592 return rc;
5593}
5594
Steve French50c2f752007-07-13 00:33:32 +00005595/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 an open handle, rather than by pathname - this is awkward due to
5597 potential access conflicts on the open, but it is unavoidable for these
5598 old servers since the only other choice is to go from 100 nanosecond DCE
5599 time and resort to the original setpathinfo level which takes the ancient
5600 DOS time format with 2 second granularity */
5601int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005602CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005603 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604{
5605 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 char *data_offset;
5607 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 __u16 params, param_offset, offset, byte_count, count;
5609
Joe Perchesf96637b2013-05-04 22:12:25 -05005610 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005611 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5612
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 if (rc)
5614 return rc;
5615
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005616 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5617 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005618
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 params = 6;
5620 pSMB->MaxSetupCount = 0;
5621 pSMB->Reserved = 0;
5622 pSMB->Flags = 0;
5623 pSMB->Timeout = 0;
5624 pSMB->Reserved2 = 0;
5625 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5626 offset = param_offset + params;
5627
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005628 data_offset = (char *)pSMB +
5629 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630
Steve French26f57362007-08-30 22:09:15 +00005631 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005633 /* BB find max SMB PDU from sess */
5634 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 pSMB->SetupCount = 1;
5636 pSMB->Reserved3 = 0;
5637 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5638 byte_count = 3 /* pad */ + params + count;
5639 pSMB->DataCount = cpu_to_le16(count);
5640 pSMB->ParameterCount = cpu_to_le16(params);
5641 pSMB->TotalDataCount = pSMB->DataCount;
5642 pSMB->TotalParameterCount = pSMB->ParameterCount;
5643 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5644 pSMB->DataOffset = cpu_to_le16(offset);
5645 pSMB->Fid = fid;
5646 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5647 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5648 else
5649 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5650 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005651 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005653 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005654 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005655 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005656 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5657 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658
Steve French50c2f752007-07-13 00:33:32 +00005659 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 since file handle passed in no longer valid */
5661
5662 return rc;
5663}
5664
Jeff Layton6d22f092008-09-23 11:48:35 -04005665int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005666CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005667 bool delete_file, __u16 fid, __u32 pid_of_opener)
5668{
5669 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5670 char *data_offset;
5671 int rc = 0;
5672 __u16 params, param_offset, offset, byte_count, count;
5673
Joe Perchesf96637b2013-05-04 22:12:25 -05005674 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005675 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5676
5677 if (rc)
5678 return rc;
5679
5680 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5681 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5682
5683 params = 6;
5684 pSMB->MaxSetupCount = 0;
5685 pSMB->Reserved = 0;
5686 pSMB->Flags = 0;
5687 pSMB->Timeout = 0;
5688 pSMB->Reserved2 = 0;
5689 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5690 offset = param_offset + params;
5691
5692 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5693
5694 count = 1;
5695 pSMB->MaxParameterCount = cpu_to_le16(2);
5696 /* BB find max SMB PDU from sess */
5697 pSMB->MaxDataCount = cpu_to_le16(1000);
5698 pSMB->SetupCount = 1;
5699 pSMB->Reserved3 = 0;
5700 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5701 byte_count = 3 /* pad */ + params + count;
5702 pSMB->DataCount = cpu_to_le16(count);
5703 pSMB->ParameterCount = cpu_to_le16(params);
5704 pSMB->TotalDataCount = pSMB->DataCount;
5705 pSMB->TotalParameterCount = pSMB->ParameterCount;
5706 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5707 pSMB->DataOffset = cpu_to_le16(offset);
5708 pSMB->Fid = fid;
5709 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5710 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005711 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005712 pSMB->ByteCount = cpu_to_le16(byte_count);
5713 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005714 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005715 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005716 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005717
5718 return rc;
5719}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720
5721int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005722CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005723 const char *fileName, const FILE_BASIC_INFO *data,
5724 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725{
5726 TRANSACTION2_SPI_REQ *pSMB = NULL;
5727 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5728 int name_len;
5729 int rc = 0;
5730 int bytes_returned = 0;
5731 char *data_offset;
5732 __u16 params, param_offset, offset, byte_count, count;
5733
Joe Perchesf96637b2013-05-04 22:12:25 -05005734 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735
5736SetTimesRetry:
5737 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5738 (void **) &pSMBr);
5739 if (rc)
5740 return rc;
5741
5742 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5743 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005744 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5745 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 name_len++; /* trailing null */
5747 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005748 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 name_len = strnlen(fileName, PATH_MAX);
5750 name_len++; /* trailing null */
5751 strncpy(pSMB->FileName, fileName, name_len);
5752 }
5753
5754 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005755 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005757 /* BB find max SMB PDU from sess structure BB */
5758 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 pSMB->MaxSetupCount = 0;
5760 pSMB->Reserved = 0;
5761 pSMB->Flags = 0;
5762 pSMB->Timeout = 0;
5763 pSMB->Reserved2 = 0;
5764 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005765 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 offset = param_offset + params;
5767 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5768 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5769 pSMB->DataOffset = cpu_to_le16(offset);
5770 pSMB->SetupCount = 1;
5771 pSMB->Reserved3 = 0;
5772 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5773 byte_count = 3 /* pad */ + params + count;
5774
5775 pSMB->DataCount = cpu_to_le16(count);
5776 pSMB->ParameterCount = cpu_to_le16(params);
5777 pSMB->TotalDataCount = pSMB->DataCount;
5778 pSMB->TotalParameterCount = pSMB->ParameterCount;
5779 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5780 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5781 else
5782 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5783 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005784 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005785 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786 pSMB->ByteCount = cpu_to_le16(byte_count);
5787 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5788 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005789 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005790 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
5792 cifs_buf_release(pSMB);
5793
5794 if (rc == -EAGAIN)
5795 goto SetTimesRetry;
5796
5797 return rc;
5798}
5799
5800/* Can not be used to set time stamps yet (due to old DOS time format) */
5801/* Can be used to set attributes */
5802#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5803 handling it anyway and NT4 was what we thought it would be needed for
5804 Do not delete it until we prove whether needed for Win9x though */
5805int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005806CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 __u16 dos_attrs, const struct nls_table *nls_codepage)
5808{
5809 SETATTR_REQ *pSMB = NULL;
5810 SETATTR_RSP *pSMBr = NULL;
5811 int rc = 0;
5812 int bytes_returned;
5813 int name_len;
5814
Joe Perchesf96637b2013-05-04 22:12:25 -05005815 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816
5817SetAttrLgcyRetry:
5818 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5819 (void **) &pSMBr);
5820 if (rc)
5821 return rc;
5822
5823 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5824 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005825 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5826 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 name_len++; /* trailing null */
5828 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005829 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 name_len = strnlen(fileName, PATH_MAX);
5831 name_len++; /* trailing null */
5832 strncpy(pSMB->fileName, fileName, name_len);
5833 }
5834 pSMB->attr = cpu_to_le16(dos_attrs);
5835 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005836 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005840 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005841 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842
5843 cifs_buf_release(pSMB);
5844
5845 if (rc == -EAGAIN)
5846 goto SetAttrLgcyRetry;
5847
5848 return rc;
5849}
5850#endif /* temporarily unneeded SetAttr legacy function */
5851
Jeff Layton654cf142009-07-09 20:02:49 -04005852static void
5853cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5854 const struct cifs_unix_set_info_args *args)
5855{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005856 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005857 u64 mode = args->mode;
5858
Eric W. Biederman49418b22013-02-06 00:57:56 -08005859 if (uid_valid(args->uid))
5860 uid = from_kuid(&init_user_ns, args->uid);
5861 if (gid_valid(args->gid))
5862 gid = from_kgid(&init_user_ns, args->gid);
5863
Jeff Layton654cf142009-07-09 20:02:49 -04005864 /*
5865 * Samba server ignores set of file size to zero due to bugs in some
5866 * older clients, but we should be precise - we use SetFileSize to
5867 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005868 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005869 * zero instead of -1 here
5870 */
5871 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5872 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5873 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5874 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5875 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005876 data_offset->Uid = cpu_to_le64(uid);
5877 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005878 /* better to leave device as zero when it is */
5879 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5880 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5881 data_offset->Permissions = cpu_to_le64(mode);
5882
5883 if (S_ISREG(mode))
5884 data_offset->Type = cpu_to_le32(UNIX_FILE);
5885 else if (S_ISDIR(mode))
5886 data_offset->Type = cpu_to_le32(UNIX_DIR);
5887 else if (S_ISLNK(mode))
5888 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5889 else if (S_ISCHR(mode))
5890 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5891 else if (S_ISBLK(mode))
5892 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5893 else if (S_ISFIFO(mode))
5894 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5895 else if (S_ISSOCK(mode))
5896 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5897}
5898
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005900CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005901 const struct cifs_unix_set_info_args *args,
5902 u16 fid, u32 pid_of_opener)
5903{
5904 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005905 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005906 int rc = 0;
5907 u16 params, param_offset, offset, byte_count, count;
5908
Joe Perchesf96637b2013-05-04 22:12:25 -05005909 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005910 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5911
5912 if (rc)
5913 return rc;
5914
5915 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5916 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5917
5918 params = 6;
5919 pSMB->MaxSetupCount = 0;
5920 pSMB->Reserved = 0;
5921 pSMB->Flags = 0;
5922 pSMB->Timeout = 0;
5923 pSMB->Reserved2 = 0;
5924 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5925 offset = param_offset + params;
5926
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005927 data_offset = (char *)pSMB +
5928 offsetof(struct smb_hdr, Protocol) + offset;
5929
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005930 count = sizeof(FILE_UNIX_BASIC_INFO);
5931
5932 pSMB->MaxParameterCount = cpu_to_le16(2);
5933 /* BB find max SMB PDU from sess */
5934 pSMB->MaxDataCount = cpu_to_le16(1000);
5935 pSMB->SetupCount = 1;
5936 pSMB->Reserved3 = 0;
5937 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5938 byte_count = 3 /* pad */ + params + count;
5939 pSMB->DataCount = cpu_to_le16(count);
5940 pSMB->ParameterCount = cpu_to_le16(params);
5941 pSMB->TotalDataCount = pSMB->DataCount;
5942 pSMB->TotalParameterCount = pSMB->ParameterCount;
5943 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5944 pSMB->DataOffset = cpu_to_le16(offset);
5945 pSMB->Fid = fid;
5946 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5947 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005948 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005949 pSMB->ByteCount = cpu_to_le16(byte_count);
5950
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005951 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005952
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005953 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005954 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005955 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5956 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005957
5958 /* Note: On -EAGAIN error only caller can retry on handle based calls
5959 since file handle passed in no longer valid */
5960
5961 return rc;
5962}
5963
5964int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005965CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005966 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005967 const struct cifs_unix_set_info_args *args,
5968 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969{
5970 TRANSACTION2_SPI_REQ *pSMB = NULL;
5971 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5972 int name_len;
5973 int rc = 0;
5974 int bytes_returned = 0;
5975 FILE_UNIX_BASIC_INFO *data_offset;
5976 __u16 params, param_offset, offset, count, byte_count;
5977
Joe Perchesf96637b2013-05-04 22:12:25 -05005978 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979setPermsRetry:
5980 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5981 (void **) &pSMBr);
5982 if (rc)
5983 return rc;
5984
5985 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5986 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005987 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005988 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 name_len++; /* trailing null */
5990 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005991 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005992 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005994 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 }
5996
5997 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005998 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006000 /* BB find max SMB PDU from sess structure BB */
6001 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002 pSMB->MaxSetupCount = 0;
6003 pSMB->Reserved = 0;
6004 pSMB->Flags = 0;
6005 pSMB->Timeout = 0;
6006 pSMB->Reserved2 = 0;
6007 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006008 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009 offset = param_offset + params;
6010 data_offset =
6011 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6012 offset);
6013 memset(data_offset, 0, count);
6014 pSMB->DataOffset = cpu_to_le16(offset);
6015 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6016 pSMB->SetupCount = 1;
6017 pSMB->Reserved3 = 0;
6018 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6019 byte_count = 3 /* pad */ + params + count;
6020 pSMB->ParameterCount = cpu_to_le16(params);
6021 pSMB->DataCount = cpu_to_le16(count);
6022 pSMB->TotalParameterCount = pSMB->ParameterCount;
6023 pSMB->TotalDataCount = pSMB->DataCount;
6024 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6025 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006026 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006027
Jeff Layton654cf142009-07-09 20:02:49 -04006028 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029
6030 pSMB->ByteCount = cpu_to_le16(byte_count);
6031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006033 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006034 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035
Steve French0d817bc2008-05-22 02:02:03 +00006036 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037 if (rc == -EAGAIN)
6038 goto setPermsRetry;
6039 return rc;
6040}
6041
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006043/*
6044 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6045 * function used by listxattr and getxattr type calls. When ea_name is set,
6046 * it looks for that attribute name and stuffs that value into the EAData
6047 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6048 * buffer. In both cases, the return value is either the length of the
6049 * resulting data or a negative error code. If EAData is a NULL pointer then
6050 * the data isn't copied to it, but the length is returned.
6051 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006053CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006054 const unsigned char *searchName, const unsigned char *ea_name,
6055 char *EAData, size_t buf_size,
6056 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057{
6058 /* BB assumes one setup word */
6059 TRANSACTION2_QPI_REQ *pSMB = NULL;
6060 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6061 int rc = 0;
6062 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006063 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006064 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006065 struct fea *temp_fea;
6066 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006067 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006068 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006069 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
Joe Perchesf96637b2013-05-04 22:12:25 -05006071 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072QAllEAsRetry:
6073 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6074 (void **) &pSMBr);
6075 if (rc)
6076 return rc;
6077
6078 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006079 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006080 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6081 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006082 list_len++; /* trailing null */
6083 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006085 list_len = strnlen(searchName, PATH_MAX);
6086 list_len++; /* trailing null */
6087 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 }
6089
Jeff Layton6e462b92010-02-10 16:18:26 -05006090 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 pSMB->TotalDataCount = 0;
6092 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006093 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006094 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 pSMB->MaxSetupCount = 0;
6096 pSMB->Reserved = 0;
6097 pSMB->Flags = 0;
6098 pSMB->Timeout = 0;
6099 pSMB->Reserved2 = 0;
6100 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006101 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 pSMB->DataCount = 0;
6103 pSMB->DataOffset = 0;
6104 pSMB->SetupCount = 1;
6105 pSMB->Reserved3 = 0;
6106 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6107 byte_count = params + 1 /* pad */ ;
6108 pSMB->TotalParameterCount = cpu_to_le16(params);
6109 pSMB->ParameterCount = pSMB->TotalParameterCount;
6110 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6111 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006112 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113 pSMB->ByteCount = cpu_to_le16(byte_count);
6114
6115 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6116 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6117 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006118 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006119 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006121
6122
6123 /* BB also check enough total bytes returned */
6124 /* BB we need to improve the validity checking
6125 of these trans2 responses */
6126
6127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006128 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006129 rc = -EIO; /* bad smb */
6130 goto QAllEAsOut;
6131 }
6132
6133 /* check that length of list is not more than bcc */
6134 /* check that each entry does not go beyond length
6135 of list */
6136 /* check that each element of each entry does not
6137 go beyond end of list */
6138 /* validate_trans2_offsets() */
6139 /* BB check if start of smb + data_offset > &bcc+ bcc */
6140
6141 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6142 ea_response_data = (struct fealist *)
6143 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6144
Jeff Layton6e462b92010-02-10 16:18:26 -05006145 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006146 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006147 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006148 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006149 goto QAllEAsOut;
6150 }
6151
Jeff Layton0cd126b2010-02-10 16:18:26 -05006152 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006153 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006154 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006155 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006156 rc = -EIO;
6157 goto QAllEAsOut;
6158 }
6159
Jeff Laytonf0d38682010-02-10 16:18:26 -05006160 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006161 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006162 temp_fea = ea_response_data->list;
6163 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006164 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006165 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006166 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006167
Jeff Layton6e462b92010-02-10 16:18:26 -05006168 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006169 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006170 /* make sure we can read name_len and value_len */
6171 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006172 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006173 rc = -EIO;
6174 goto QAllEAsOut;
6175 }
6176
6177 name_len = temp_fea->name_len;
6178 value_len = le16_to_cpu(temp_fea->value_len);
6179 list_len -= name_len + 1 + value_len;
6180 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006181 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006182 rc = -EIO;
6183 goto QAllEAsOut;
6184 }
6185
Jeff Layton31c05192010-02-10 16:18:26 -05006186 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006187 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006188 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006189 temp_ptr += name_len + 1;
6190 rc = value_len;
6191 if (buf_size == 0)
6192 goto QAllEAsOut;
6193 if ((size_t)value_len > buf_size) {
6194 rc = -ERANGE;
6195 goto QAllEAsOut;
6196 }
6197 memcpy(EAData, temp_ptr, value_len);
6198 goto QAllEAsOut;
6199 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006200 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006201 /* account for prefix user. and trailing null */
6202 rc += (5 + 1 + name_len);
6203 if (rc < (int) buf_size) {
6204 memcpy(EAData, "user.", 5);
6205 EAData += 5;
6206 memcpy(EAData, temp_ptr, name_len);
6207 EAData += name_len;
6208 /* null terminate name */
6209 *EAData = 0;
6210 ++EAData;
6211 } else if (buf_size == 0) {
6212 /* skip copy - calc size only */
6213 } else {
6214 /* stop before overrun buffer */
6215 rc = -ERANGE;
6216 break;
6217 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006218 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006219 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006220 temp_fea = (struct fea *)temp_ptr;
6221 }
6222
Jeff Layton31c05192010-02-10 16:18:26 -05006223 /* didn't find the named attribute */
6224 if (ea_name)
6225 rc = -ENODATA;
6226
Jeff Laytonf0d38682010-02-10 16:18:26 -05006227QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006228 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 if (rc == -EAGAIN)
6230 goto QAllEAsRetry;
6231
6232 return (ssize_t)rc;
6233}
6234
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006236CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6237 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006238 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6239 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240{
6241 struct smb_com_transaction2_spi_req *pSMB = NULL;
6242 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6243 struct fealist *parm_data;
6244 int name_len;
6245 int rc = 0;
6246 int bytes_returned = 0;
6247 __u16 params, param_offset, byte_count, offset, count;
6248
Joe Perchesf96637b2013-05-04 22:12:25 -05006249 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250SetEARetry:
6251 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6252 (void **) &pSMBr);
6253 if (rc)
6254 return rc;
6255
6256 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6257 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006258 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6259 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 name_len++; /* trailing null */
6261 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006262 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263 name_len = strnlen(fileName, PATH_MAX);
6264 name_len++; /* trailing null */
6265 strncpy(pSMB->FileName, fileName, name_len);
6266 }
6267
6268 params = 6 + name_len;
6269
6270 /* done calculating parms using name_len of file name,
6271 now use name_len to calculate length of ea name
6272 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006273 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 name_len = 0;
6275 else
Steve French50c2f752007-07-13 00:33:32 +00006276 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006278 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006280 /* BB find max SMB PDU from sess */
6281 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 pSMB->MaxSetupCount = 0;
6283 pSMB->Reserved = 0;
6284 pSMB->Flags = 0;
6285 pSMB->Timeout = 0;
6286 pSMB->Reserved2 = 0;
6287 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006288 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 offset = param_offset + params;
6290 pSMB->InformationLevel =
6291 cpu_to_le16(SMB_SET_FILE_EA);
6292
6293 parm_data =
6294 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6295 offset);
6296 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6297 pSMB->DataOffset = cpu_to_le16(offset);
6298 pSMB->SetupCount = 1;
6299 pSMB->Reserved3 = 0;
6300 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6301 byte_count = 3 /* pad */ + params + count;
6302 pSMB->DataCount = cpu_to_le16(count);
6303 parm_data->list_len = cpu_to_le32(count);
6304 parm_data->list[0].EA_flags = 0;
6305 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006306 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006308 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006309 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310 parm_data->list[0].name[name_len] = 0;
6311 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6312 /* caller ensures that ea_value_len is less than 64K but
6313 we need to ensure that it fits within the smb */
6314
Steve French50c2f752007-07-13 00:33:32 +00006315 /*BB add length check to see if it would fit in
6316 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006317 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6318 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006319 memcpy(parm_data->list[0].name+name_len+1,
6320 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321
6322 pSMB->TotalDataCount = pSMB->DataCount;
6323 pSMB->ParameterCount = cpu_to_le16(params);
6324 pSMB->TotalParameterCount = pSMB->ParameterCount;
6325 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006326 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 pSMB->ByteCount = cpu_to_le16(byte_count);
6328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6329 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006330 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006331 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
6333 cifs_buf_release(pSMB);
6334
6335 if (rc == -EAGAIN)
6336 goto SetEARetry;
6337
6338 return rc;
6339}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340#endif
Steve French0eff0e22011-02-24 05:39:23 +00006341
6342#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6343/*
6344 * Years ago the kernel added a "dnotify" function for Samba server,
6345 * to allow network clients (such as Windows) to display updated
6346 * lists of files in directory listings automatically when
6347 * files are added by one user when another user has the
6348 * same directory open on their desktop. The Linux cifs kernel
6349 * client hooked into the kernel side of this interface for
6350 * the same reason, but ironically when the VFS moved from
6351 * "dnotify" to "inotify" it became harder to plug in Linux
6352 * network file system clients (the most obvious use case
6353 * for notify interfaces is when multiple users can update
6354 * the contents of the same directory - exactly what network
6355 * file systems can do) although the server (Samba) could
6356 * still use it. For the short term we leave the worker
6357 * function ifdeffed out (below) until inotify is fixed
6358 * in the VFS to make it easier to plug in network file
6359 * system clients. If inotify turns out to be permanently
6360 * incompatible for network fs clients, we could instead simply
6361 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6362 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006363int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006364 const int notify_subdirs, const __u16 netfid,
6365 __u32 filter, struct file *pfile, int multishot,
6366 const struct nls_table *nls_codepage)
6367{
6368 int rc = 0;
6369 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6370 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6371 struct dir_notify_req *dnotify_req;
6372 int bytes_returned;
6373
Joe Perchesf96637b2013-05-04 22:12:25 -05006374 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006375 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6376 (void **) &pSMBr);
6377 if (rc)
6378 return rc;
6379
6380 pSMB->TotalParameterCount = 0 ;
6381 pSMB->TotalDataCount = 0;
6382 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006383 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006384 pSMB->MaxSetupCount = 4;
6385 pSMB->Reserved = 0;
6386 pSMB->ParameterOffset = 0;
6387 pSMB->DataCount = 0;
6388 pSMB->DataOffset = 0;
6389 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6390 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6391 pSMB->ParameterCount = pSMB->TotalParameterCount;
6392 if (notify_subdirs)
6393 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6394 pSMB->Reserved2 = 0;
6395 pSMB->CompletionFilter = cpu_to_le32(filter);
6396 pSMB->Fid = netfid; /* file handle always le */
6397 pSMB->ByteCount = 0;
6398
6399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6400 (struct smb_hdr *)pSMBr, &bytes_returned,
6401 CIFS_ASYNC_OP);
6402 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006403 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006404 } else {
6405 /* Add file to outstanding requests */
6406 /* BB change to kmem cache alloc */
6407 dnotify_req = kmalloc(
6408 sizeof(struct dir_notify_req),
6409 GFP_KERNEL);
6410 if (dnotify_req) {
6411 dnotify_req->Pid = pSMB->hdr.Pid;
6412 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6413 dnotify_req->Mid = pSMB->hdr.Mid;
6414 dnotify_req->Tid = pSMB->hdr.Tid;
6415 dnotify_req->Uid = pSMB->hdr.Uid;
6416 dnotify_req->netfid = netfid;
6417 dnotify_req->pfile = pfile;
6418 dnotify_req->filter = filter;
6419 dnotify_req->multishot = multishot;
6420 spin_lock(&GlobalMid_Lock);
6421 list_add_tail(&dnotify_req->lhead,
6422 &GlobalDnotifyReqList);
6423 spin_unlock(&GlobalMid_Lock);
6424 } else
6425 rc = -ENOMEM;
6426 }
6427 cifs_buf_release(pSMB);
6428 return rc;
6429}
6430#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */