blob: 5dd4f8a51e0cd210e8f4d296ad74d942e712e757 [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 Layton2190eca2013-05-26 07:00:57 -0400420#ifdef CONFIG_CIFS_WEAK_PW_HASH
421static int
422decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
423 unsigned int secFlags)
424{
425 __s16 tmp;
426 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
427
428 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
429 return -EOPNOTSUPP;
430
431 if ((secFlags & CIFSSEC_MAY_LANMAN) || (secFlags & CIFSSEC_MAY_PLNTXT))
432 server->secType = LANMAN;
433 else {
434 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
435 return -EOPNOTSUPP;
436 }
437 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
438 server->maxReq = min_t(unsigned int,
439 le16_to_cpu(rsp->MaxMpxCount),
440 cifs_max_pending);
441 set_credits(server, server->maxReq);
442 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
443 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
444 /* even though we do not use raw we might as well set this
445 accurately, in case we ever find a need for it */
446 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
447 server->max_rw = 0xFF00;
448 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
449 } else {
450 server->max_rw = 0;/* do not need to use raw anyway */
451 server->capabilities = CAP_MPX_MODE;
452 }
453 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
454 if (tmp == -1) {
455 /* OS/2 often does not set timezone therefore
456 * we must use server time to calc time zone.
457 * Could deviate slightly from the right zone.
458 * Smallest defined timezone difference is 15 minutes
459 * (i.e. Nepal). Rounding up/down is done to match
460 * this requirement.
461 */
462 int val, seconds, remain, result;
463 struct timespec ts, utc;
464 utc = CURRENT_TIME;
465 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
466 rsp->SrvTime.Time, 0);
467 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
468 (int)ts.tv_sec, (int)utc.tv_sec,
469 (int)(utc.tv_sec - ts.tv_sec));
470 val = (int)(utc.tv_sec - ts.tv_sec);
471 seconds = abs(val);
472 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
473 remain = seconds % MIN_TZ_ADJ;
474 if (remain >= (MIN_TZ_ADJ / 2))
475 result += MIN_TZ_ADJ;
476 if (val < 0)
477 result = -result;
478 server->timeAdj = result;
479 } else {
480 server->timeAdj = (int)tmp;
481 server->timeAdj *= 60; /* also in seconds */
482 }
483 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
484
485
486 /* BB get server time for time conversions and add
487 code to use it and timezone since this is not UTC */
488
489 if (rsp->EncryptionKeyLength ==
490 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
491 memcpy(server->cryptkey, rsp->EncryptionKey,
492 CIFS_CRYPTO_KEY_SIZE);
493 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
494 return -EIO; /* need cryptkey unless plain text */
495 }
496
497 cifs_dbg(FYI, "LANMAN negotiated\n");
498 return 0;
499}
500#else
501static inline int
502decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
503 unsigned int secFlags)
504{
505 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
506 return -EOPNOTSUPP;
507}
508#endif
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400511CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513 NEGOTIATE_REQ *pSMB;
514 NEGOTIATE_RSP *pSMBr;
515 int rc = 0;
516 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000517 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400518 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000520 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Jeff Layton3534b852013-05-24 07:41:01 -0400522 if (!server) {
523 WARN(1, "%s: server is NULL!\n", __func__);
524 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
Jeff Layton3534b852013-05-24 07:41:01 -0400526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
528 (void **) &pSMB, (void **) &pSMBr);
529 if (rc)
530 return rc;
Steve French750d1152006-06-27 06:28:30 +0000531
532 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000533 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000534 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000535 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400536 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000537
Joe Perchesf96637b2013-05-04 22:12:25 -0500538 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000539
Pavel Shilovsky88257362012-05-23 14:01:59 +0400540 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000541 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000542
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000543 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000544 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000545 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500546 cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
Steve Frencha0136892007-10-04 20:05:09 +0000547 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500548 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000549 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
550 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500551 cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000552 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
553 }
Steve French50c2f752007-07-13 00:33:32 +0000554
Steve French39798772006-05-31 22:40:51 +0000555 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000556 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000557 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
558 count += strlen(protocols[i].name) + 1;
559 /* null at end of source and target buffers anyway */
560 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000561 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 pSMB->ByteCount = cpu_to_le16(count);
563
564 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000566 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000567 goto neg_err_exit;
568
Jeff Layton9bf67e52010-04-24 07:57:46 -0400569 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500570 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000571 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400572 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000573 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000574 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000575 could not negotiate a common dialect */
576 rc = -EOPNOTSUPP;
577 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000578 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Layton2190eca2013-05-26 07:00:57 -0400579 rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
580 if (!rc)
581 goto signing_check;
582 else
583 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000584 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000585 /* unknown wct */
586 rc = -EOPNOTSUPP;
587 goto neg_err_exit;
588 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400589 /* else wct == 17, NTLM or better */
590
Steve French96daf2b2011-05-27 04:34:02 +0000591 server->sec_mode = pSMBr->SecurityMode;
592 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500593 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000594
Steve French96daf2b2011-05-27 04:34:02 +0000595 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000596#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000597 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000598#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500599 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000600
Steve French790fe572007-07-07 19:25:05 +0000601 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000602 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000603 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000604 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000605 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000606 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000607 else if (secFlags & CIFSSEC_MAY_KRB5)
608 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000609 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000610 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000611 else if (secFlags & CIFSSEC_MAY_LANMAN)
612 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000613 else {
614 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500615 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000616 goto neg_err_exit;
617 }
618 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000619
Steve French254e55e2006-06-04 05:53:15 +0000620 /* one byte, so no need to convert this or EncryptionKeyLen from
621 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300622 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
623 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400624 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000625 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400626 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000627 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500628 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000629 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000630 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
631 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400632
633 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE)
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500634 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000635 CIFS_CRYPTO_KEY_SIZE);
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400636 else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000637 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400638 (pSMBr->EncryptionKeyLength == 0))
639 rc = decode_ext_sec_blob(server, pSMBr);
640 else if (server->sec_mode & SECMODE_PW_ENCRYPT)
Steve French07cc6cf2011-05-27 04:12:29 +0000641 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400642 else
Steve French254e55e2006-06-04 05:53:15 +0000643 server->capabilities &= ~CAP_EXTENDED_SECURITY;
644
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400645 if (rc)
646 goto neg_err_exit;
647
Steve French254e55e2006-06-04 05:53:15 +0000648signing_check:
Steve French762e5ab2007-06-28 18:41:42 +0000649 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
650 /* MUST_SIGN already includes the MAY_SIGN FLAG
651 so if this is zero it means that signing is disabled */
Joe Perchesf96637b2013-05-04 22:12:25 -0500652 cifs_dbg(FYI, "Signing disabled\n");
Steve French96daf2b2011-05-27 04:34:02 +0000653 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500654 cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
Steve Frenchabb63d62007-10-18 02:58:40 +0000655 rc = -EOPNOTSUPP;
656 }
Steve French96daf2b2011-05-27 04:34:02 +0000657 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000659 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
660 /* signing required */
Joe Perchesf96637b2013-05-04 22:12:25 -0500661 cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000662 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000663 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500664 cifs_dbg(VFS, "signing required but server lacks support\n");
Jeff38c10a12007-07-06 21:10:07 +0000665 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000666 } else
Steve French96daf2b2011-05-27 04:34:02 +0000667 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000668 } else {
669 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000670 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
671 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000672 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
Steve French50c2f752007-07-13 00:33:32 +0000674
675neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700676 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000677
Joe Perchesf96637b2013-05-04 22:12:25 -0500678 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 return rc;
680}
681
682int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400683CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
685 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Joe Perchesf96637b2013-05-04 22:12:25 -0500688 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500689
690 /* BB: do we need to check this? These should never be NULL. */
691 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
692 return -EIO;
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500695 * No need to return error on this operation if tid invalidated and
696 * closed on server already e.g. due to tcp session crashing. Also,
697 * the tcon is no longer on the list, so no need to take lock before
698 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 */
Steve French268875b2009-06-25 00:29:21 +0000700 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000701 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Steve French50c2f752007-07-13 00:33:32 +0000703 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700704 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500705 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return rc;
Steve French133672e2007-11-13 22:41:37 +0000707
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400708 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500710 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Steve French50c2f752007-07-13 00:33:32 +0000712 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500713 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 if (rc == -EAGAIN)
715 rc = 0;
716
717 return rc;
718}
719
Jeff Layton766fdbb2011-01-11 07:24:21 -0500720/*
721 * This is a no-op for now. We're not really interested in the reply, but
722 * rather in the fact that the server sent one and that server->lstrp
723 * gets updated.
724 *
725 * FIXME: maybe we should consider checking that the reply matches request?
726 */
727static void
728cifs_echo_callback(struct mid_q_entry *mid)
729{
730 struct TCP_Server_Info *server = mid->callback_data;
731
732 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400733 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500734}
735
736int
737CIFSSMBEcho(struct TCP_Server_Info *server)
738{
739 ECHO_REQ *smb;
740 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400741 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700742 struct smb_rqst rqst = { .rq_iov = &iov,
743 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500744
Joe Perchesf96637b2013-05-04 22:12:25 -0500745 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
747 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
748 if (rc)
749 return rc;
750
751 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000752 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500753 smb->hdr.WordCount = 1;
754 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400755 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500756 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000757 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400758 iov.iov_base = smb;
759 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500760
Jeff Laytonfec344e2012-09-18 16:20:35 -0700761 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400762 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500763 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500764 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500765
766 cifs_small_buf_release(smb);
767
768 return rc;
769}
770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400772CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 LOGOFF_ANDX_REQ *pSMB;
775 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Joe Perchesf96637b2013-05-04 22:12:25 -0500777 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500778
779 /*
780 * BB: do we need to check validity of ses and server? They should
781 * always be valid since we have an active reference. If not, that
782 * should probably be a BUG()
783 */
784 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return -EIO;
786
Steve Frenchd7b619c2010-02-25 05:36:46 +0000787 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000788 if (ses->need_reconnect)
789 goto session_already_dead; /* no need to send SMBlogoff if uid
790 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
792 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000793 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return rc;
795 }
796
Pavel Shilovsky88257362012-05-23 14:01:59 +0400797 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700798
Steve French96daf2b2011-05-27 04:34:02 +0000799 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
801 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
803 pSMB->hdr.Uid = ses->Suid;
804
805 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400806 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000807session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000808 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
810 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000811 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 error */
813 if (rc == -EAGAIN)
814 rc = 0;
815 return rc;
816}
817
818int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400819CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
820 const char *fileName, __u16 type,
821 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000822{
823 TRANSACTION2_SPI_REQ *pSMB = NULL;
824 TRANSACTION2_SPI_RSP *pSMBr = NULL;
825 struct unlink_psx_rq *pRqD;
826 int name_len;
827 int rc = 0;
828 int bytes_returned = 0;
829 __u16 params, param_offset, offset, byte_count;
830
Joe Perchesf96637b2013-05-04 22:12:25 -0500831 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000832PsxDelete:
833 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
834 (void **) &pSMBr);
835 if (rc)
836 return rc;
837
838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
839 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600840 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
841 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000842 name_len++; /* trailing null */
843 name_len *= 2;
844 } else { /* BB add path length overrun check */
845 name_len = strnlen(fileName, PATH_MAX);
846 name_len++; /* trailing null */
847 strncpy(pSMB->FileName, fileName, name_len);
848 }
849
850 params = 6 + name_len;
851 pSMB->MaxParameterCount = cpu_to_le16(2);
852 pSMB->MaxDataCount = 0; /* BB double check this with jra */
853 pSMB->MaxSetupCount = 0;
854 pSMB->Reserved = 0;
855 pSMB->Flags = 0;
856 pSMB->Timeout = 0;
857 pSMB->Reserved2 = 0;
858 param_offset = offsetof(struct smb_com_transaction2_spi_req,
859 InformationLevel) - 4;
860 offset = param_offset + params;
861
862 /* Setup pointer to Request Data (inode type) */
863 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
864 pRqD->type = cpu_to_le16(type);
865 pSMB->ParameterOffset = cpu_to_le16(param_offset);
866 pSMB->DataOffset = cpu_to_le16(offset);
867 pSMB->SetupCount = 1;
868 pSMB->Reserved3 = 0;
869 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
870 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
871
872 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
873 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
874 pSMB->ParameterCount = cpu_to_le16(params);
875 pSMB->TotalParameterCount = pSMB->ParameterCount;
876 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
877 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000878 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000879 pSMB->ByteCount = cpu_to_le16(byte_count);
880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
881 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000882 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500883 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000884 cifs_buf_release(pSMB);
885
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400886 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000887
888 if (rc == -EAGAIN)
889 goto PsxDelete;
890
891 return rc;
892}
893
894int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700895CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
896 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
898 DELETE_FILE_REQ *pSMB = NULL;
899 DELETE_FILE_RSP *pSMBr = NULL;
900 int rc = 0;
901 int bytes_returned;
902 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700903 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
905DelFileRetry:
906 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
907 (void **) &pSMBr);
908 if (rc)
909 return rc;
910
911 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700912 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
913 PATH_MAX, cifs_sb->local_nls,
914 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 name_len++; /* trailing null */
916 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700917 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700918 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700920 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 }
922 pSMB->SearchAttributes =
923 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
924 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000925 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 pSMB->ByteCount = cpu_to_le16(name_len + 1);
927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400929 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000930 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500931 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
933 cifs_buf_release(pSMB);
934 if (rc == -EAGAIN)
935 goto DelFileRetry;
936
937 return rc;
938}
939
940int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400941CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
942 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
944 DELETE_DIRECTORY_REQ *pSMB = NULL;
945 DELETE_DIRECTORY_RSP *pSMBr = NULL;
946 int rc = 0;
947 int bytes_returned;
948 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400949 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Joe Perchesf96637b2013-05-04 22:12:25 -0500951 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952RmDirRetry:
953 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
954 (void **) &pSMBr);
955 if (rc)
956 return rc;
957
958 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400959 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
960 PATH_MAX, cifs_sb->local_nls,
961 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 name_len++; /* trailing null */
963 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700964 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400965 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400967 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 }
969
970 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000971 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 pSMB->ByteCount = cpu_to_le16(name_len + 1);
973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400975 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000976 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500977 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979 cifs_buf_release(pSMB);
980 if (rc == -EAGAIN)
981 goto RmDirRetry;
982 return rc;
983}
984
985int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300986CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
987 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
989 int rc = 0;
990 CREATE_DIRECTORY_REQ *pSMB = NULL;
991 CREATE_DIRECTORY_RSP *pSMBr = NULL;
992 int bytes_returned;
993 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300994 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Joe Perchesf96637b2013-05-04 22:12:25 -0500996 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997MkDirRetry:
998 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
999 (void **) &pSMBr);
1000 if (rc)
1001 return rc;
1002
1003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001004 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001005 PATH_MAX, cifs_sb->local_nls,
1006 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 name_len++; /* trailing null */
1008 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001009 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 name_len = strnlen(name, PATH_MAX);
1011 name_len++; /* trailing null */
1012 strncpy(pSMB->DirName, name, name_len);
1013 }
1014
1015 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001016 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001020 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001021 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001022 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 cifs_buf_release(pSMB);
1025 if (rc == -EAGAIN)
1026 goto MkDirRetry;
1027 return rc;
1028}
1029
Steve French2dd29d32007-04-23 22:07:35 +00001030int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001031CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1032 __u32 posix_flags, __u64 mode, __u16 *netfid,
1033 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1034 const char *name, const struct nls_table *nls_codepage,
1035 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001036{
1037 TRANSACTION2_SPI_REQ *pSMB = NULL;
1038 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1039 int name_len;
1040 int rc = 0;
1041 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001042 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001043 OPEN_PSX_REQ *pdata;
1044 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001045
Joe Perchesf96637b2013-05-04 22:12:25 -05001046 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001047PsxCreat:
1048 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1049 (void **) &pSMBr);
1050 if (rc)
1051 return rc;
1052
1053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1054 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001055 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1056 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001057 name_len++; /* trailing null */
1058 name_len *= 2;
1059 } else { /* BB improve the check for buffer overruns BB */
1060 name_len = strnlen(name, PATH_MAX);
1061 name_len++; /* trailing null */
1062 strncpy(pSMB->FileName, name, name_len);
1063 }
1064
1065 params = 6 + name_len;
1066 count = sizeof(OPEN_PSX_REQ);
1067 pSMB->MaxParameterCount = cpu_to_le16(2);
1068 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1069 pSMB->MaxSetupCount = 0;
1070 pSMB->Reserved = 0;
1071 pSMB->Flags = 0;
1072 pSMB->Timeout = 0;
1073 pSMB->Reserved2 = 0;
1074 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001075 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001076 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001078 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001080 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001081 pdata->OpenFlags = cpu_to_le32(*pOplock);
1082 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1083 pSMB->DataOffset = cpu_to_le16(offset);
1084 pSMB->SetupCount = 1;
1085 pSMB->Reserved3 = 0;
1086 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1087 byte_count = 3 /* pad */ + params + count;
1088
1089 pSMB->DataCount = cpu_to_le16(count);
1090 pSMB->ParameterCount = cpu_to_le16(params);
1091 pSMB->TotalDataCount = pSMB->DataCount;
1092 pSMB->TotalParameterCount = pSMB->ParameterCount;
1093 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1094 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001095 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001096 pSMB->ByteCount = cpu_to_le16(byte_count);
1097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1099 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001100 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001101 goto psx_create_err;
1102 }
1103
Joe Perchesf96637b2013-05-04 22:12:25 -05001104 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1106
Jeff Layton820a8032011-05-04 08:05:26 -04001107 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001108 rc = -EIO; /* bad smb */
1109 goto psx_create_err;
1110 }
1111
1112 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001113 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001114 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001115
Steve French2dd29d32007-04-23 22:07:35 +00001116 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001117 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001118 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1119 /* Let caller know file was created so we can set the mode. */
1120 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001121 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001122 *pOplock |= CIFS_CREATE_ACTION;
1123 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001124 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1125 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001126 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001127 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001128 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001129 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001130 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001131 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001132 goto psx_create_err;
1133 }
Steve French50c2f752007-07-13 00:33:32 +00001134 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001135 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001136 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001137 }
Steve French2dd29d32007-04-23 22:07:35 +00001138
1139psx_create_err:
1140 cifs_buf_release(pSMB);
1141
Steve French65bc98b2009-07-10 15:27:25 +00001142 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001143 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001144 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001145 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001146
1147 if (rc == -EAGAIN)
1148 goto PsxCreat;
1149
Steve French50c2f752007-07-13 00:33:32 +00001150 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001151}
1152
Steve Frencha9d02ad2005-08-24 23:06:05 -07001153static __u16 convert_disposition(int disposition)
1154{
1155 __u16 ofun = 0;
1156
1157 switch (disposition) {
1158 case FILE_SUPERSEDE:
1159 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1160 break;
1161 case FILE_OPEN:
1162 ofun = SMBOPEN_OAPPEND;
1163 break;
1164 case FILE_CREATE:
1165 ofun = SMBOPEN_OCREATE;
1166 break;
1167 case FILE_OPEN_IF:
1168 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1169 break;
1170 case FILE_OVERWRITE:
1171 ofun = SMBOPEN_OTRUNC;
1172 break;
1173 case FILE_OVERWRITE_IF:
1174 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1175 break;
1176 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001177 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001178 ofun = SMBOPEN_OAPPEND; /* regular open */
1179 }
1180 return ofun;
1181}
1182
Jeff Layton35fc37d2008-05-14 10:22:03 -07001183static int
1184access_flags_to_smbopen_mode(const int access_flags)
1185{
1186 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1187
1188 if (masked_flags == GENERIC_READ)
1189 return SMBOPEN_READ;
1190 else if (masked_flags == GENERIC_WRITE)
1191 return SMBOPEN_WRITE;
1192
1193 /* just go for read/write */
1194 return SMBOPEN_READWRITE;
1195}
1196
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001198SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001199 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001200 const int access_flags, const int create_options, __u16 *netfid,
1201 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001202 const struct nls_table *nls_codepage, int remap)
1203{
1204 int rc = -EACCES;
1205 OPENX_REQ *pSMB = NULL;
1206 OPENX_RSP *pSMBr = NULL;
1207 int bytes_returned;
1208 int name_len;
1209 __u16 count;
1210
1211OldOpenRetry:
1212 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1213 (void **) &pSMBr);
1214 if (rc)
1215 return rc;
1216
1217 pSMB->AndXCommand = 0xFF; /* none */
1218
1219 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1220 count = 1; /* account for one byte pad to word boundary */
1221 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001222 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1223 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001224 name_len++; /* trailing null */
1225 name_len *= 2;
1226 } else { /* BB improve check for buffer overruns BB */
1227 count = 0; /* no pad */
1228 name_len = strnlen(fileName, PATH_MAX);
1229 name_len++; /* trailing null */
1230 strncpy(pSMB->fileName, fileName, name_len);
1231 }
1232 if (*pOplock & REQ_OPLOCK)
1233 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001234 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001236
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001238 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1240 /* set file as system file if special file such
1241 as fifo and server expecting SFU style and
1242 no Unix extensions */
1243
Steve French790fe572007-07-07 19:25:05 +00001244 if (create_options & CREATE_OPTION_SPECIAL)
1245 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001246 else /* BB FIXME BB */
1247 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248
Jeff Layton67750fb2008-05-09 22:28:02 +00001249 if (create_options & CREATE_OPTION_READONLY)
1250 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251
1252 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001253/* pSMB->CreateOptions = cpu_to_le32(create_options &
1254 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001256
1257 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001258 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001260 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261
1262 pSMB->ByteCount = cpu_to_le16(count);
1263 /* long_op set to 1 to allow for oplock break timeouts */
1264 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001265 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001266 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001268 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 } else {
1270 /* BB verify if wct == 15 */
1271
Steve French582d21e2008-05-13 04:54:12 +00001272/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273
1274 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1275 /* Let caller know file was created so we can set the mode. */
1276 /* Do we care about the CreateAction in any other cases? */
1277 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001278/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 *pOplock |= CIFS_CREATE_ACTION; */
1280 /* BB FIXME END */
1281
Steve French790fe572007-07-07 19:25:05 +00001282 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1284 pfile_info->LastAccessTime = 0; /* BB fixme */
1285 pfile_info->LastWriteTime = 0; /* BB fixme */
1286 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001287 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001288 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001289 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001290 pfile_info->AllocationSize =
1291 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1292 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001293 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001294 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001295 }
1296 }
1297
1298 cifs_buf_release(pSMB);
1299 if (rc == -EAGAIN)
1300 goto OldOpenRetry;
1301 return rc;
1302}
1303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001305CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001307 const int access_flags, const int create_options, __u16 *netfid,
1308 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001309 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
1311 int rc = -EACCES;
1312 OPEN_REQ *pSMB = NULL;
1313 OPEN_RSP *pSMBr = NULL;
1314 int bytes_returned;
1315 int name_len;
1316 __u16 count;
1317
1318openRetry:
1319 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1320 (void **) &pSMBr);
1321 if (rc)
1322 return rc;
1323
1324 pSMB->AndXCommand = 0xFF; /* none */
1325
1326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1327 count = 1; /* account for one byte pad to word boundary */
1328 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001329 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1330 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 name_len++; /* trailing null */
1332 name_len *= 2;
1333 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001334 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 count = 0; /* no pad */
1336 name_len = strnlen(fileName, PATH_MAX);
1337 name_len++; /* trailing null */
1338 pSMB->NameLength = cpu_to_le16(name_len);
1339 strncpy(pSMB->fileName, fileName, name_len);
1340 }
1341 if (*pOplock & REQ_OPLOCK)
1342 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001343 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1346 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001347 /* set file as system file if special file such
1348 as fifo and server expecting SFU style and
1349 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001350 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001351 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1352 else
1353 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 /* XP does not handle ATTR_POSIX_SEMANTICS */
1356 /* but it helps speed up case sensitive checks for other
1357 servers such as Samba */
1358 if (tcon->ses->capabilities & CAP_UNIX)
1359 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1360
Jeff Layton67750fb2008-05-09 22:28:02 +00001361 if (create_options & CREATE_OPTION_READONLY)
1362 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1365 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001366 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001367 /* BB Expirement with various impersonation levels and verify */
1368 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 pSMB->SecurityFlags =
1370 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1371
1372 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001373 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 pSMB->ByteCount = cpu_to_le16(count);
1376 /* long_op set to 1 to allow for oplock break timeouts */
1377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001378 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001379 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001381 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 } else {
Steve French09d1db52005-04-28 22:41:08 -07001383 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1385 /* Let caller know file was created so we can set the mode. */
1386 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001387 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001388 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001389 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001390 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1391 36 /* CreationTime to Attributes */);
1392 /* the file_info buf is endian converted by caller */
1393 pfile_info->AllocationSize = pSMBr->AllocationSize;
1394 pfile_info->EndOfFile = pSMBr->EndOfFile;
1395 pfile_info->NumberOfLinks = cpu_to_le32(1);
1396 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 cifs_buf_release(pSMB);
1401 if (rc == -EAGAIN)
1402 goto openRetry;
1403 return rc;
1404}
1405
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001406/*
1407 * Discard any remaining data in the current SMB. To do this, we borrow the
1408 * current bigbuf.
1409 */
1410static int
1411cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1412{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001413 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001414 int remaining = rfclen + 4 - server->total_read;
1415 struct cifs_readdata *rdata = mid->callback_data;
1416
1417 while (remaining > 0) {
1418 int length;
1419
1420 length = cifs_read_from_socket(server, server->bigbuf,
1421 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001422 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001423 if (length < 0)
1424 return length;
1425 server->total_read += length;
1426 remaining -= length;
1427 }
1428
1429 dequeue_mid(mid, rdata->result);
1430 return 0;
1431}
1432
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001433int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001434cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1435{
1436 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001437 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001439 char *buf = server->smallbuf;
1440 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001441
Joe Perchesf96637b2013-05-04 22:12:25 -05001442 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1443 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001444
1445 /*
1446 * read the rest of READ_RSP header (sans Data array), or whatever we
1447 * can if there's not enough data. At this point, we've read down to
1448 * the Mid.
1449 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001450 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001451 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001452
Jeff Layton58195752012-09-19 06:22:34 -07001453 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1454 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001455
Jeff Layton58195752012-09-19 06:22:34 -07001456 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 if (length < 0)
1458 return length;
1459 server->total_read += length;
1460
1461 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001462 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001464 cifs_dbg(FYI, "%s: server returned error %d\n",
1465 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001466 return cifs_readv_discard(server, mid);
1467 }
1468
1469 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001470 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001471 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1472 __func__, server->total_read,
1473 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001474 rdata->result = -EIO;
1475 return cifs_readv_discard(server, mid);
1476 }
1477
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001478 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479 if (data_offset < server->total_read) {
1480 /*
1481 * win2k8 sometimes sends an offset of 0 when the read
1482 * is beyond the EOF. Treat it as if the data starts just after
1483 * the header.
1484 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001485 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1486 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001487 data_offset = server->total_read;
1488 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1489 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001490 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1491 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001492 rdata->result = -EIO;
1493 return cifs_readv_discard(server, mid);
1494 }
1495
Joe Perchesf96637b2013-05-04 22:12:25 -05001496 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1497 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001498
1499 len = data_offset - server->total_read;
1500 if (len > 0) {
1501 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001502 rdata->iov.iov_base = buf + server->total_read;
1503 rdata->iov.iov_len = len;
1504 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001505 if (length < 0)
1506 return length;
1507 server->total_read += length;
1508 }
1509
1510 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001511 rdata->iov.iov_base = buf;
1512 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001513 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1514 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001515
1516 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001517 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001518 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519 /* data_len is corrupt -- discard frame */
1520 rdata->result = -EIO;
1521 return cifs_readv_discard(server, mid);
1522 }
1523
Jeff Layton8321fec2012-09-19 06:22:32 -07001524 length = rdata->read_into_pages(server, rdata, data_len);
1525 if (length < 0)
1526 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001527
Jeff Layton8321fec2012-09-19 06:22:32 -07001528 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529 rdata->bytes = length;
1530
Joe Perchesf96637b2013-05-04 22:12:25 -05001531 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1532 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001533
1534 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001535 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536 return cifs_readv_discard(server, mid);
1537
1538 dequeue_mid(mid, false);
1539 return length;
1540}
1541
1542static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543cifs_readv_callback(struct mid_q_entry *mid)
1544{
1545 struct cifs_readdata *rdata = mid->callback_data;
1546 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1547 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001548 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1549 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001550 .rq_pages = rdata->pages,
1551 .rq_npages = rdata->nr_pages,
1552 .rq_pagesz = rdata->pagesz,
1553 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001554
Joe Perchesf96637b2013-05-04 22:12:25 -05001555 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1556 __func__, mid->mid, mid->mid_state, rdata->result,
1557 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001559 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560 case MID_RESPONSE_RECEIVED:
1561 /* result already set, check signature */
1562 if (server->sec_mode &
1563 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001564 int rc = 0;
1565
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001566 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001567 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001568 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001569 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1570 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001571 }
1572 /* FIXME: should this be counted toward the initiating task? */
1573 task_io_account_read(rdata->bytes);
1574 cifs_stats_bytes_read(tcon, rdata->bytes);
1575 break;
1576 case MID_REQUEST_SUBMITTED:
1577 case MID_RETRY_NEEDED:
1578 rdata->result = -EAGAIN;
1579 break;
1580 default:
1581 rdata->result = -EIO;
1582 }
1583
Jeff Laytonda472fc2012-03-23 14:40:53 -04001584 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001586 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587}
1588
1589/* cifs_async_readv - send an async write, and set up mid to handle result */
1590int
1591cifs_async_readv(struct cifs_readdata *rdata)
1592{
1593 int rc;
1594 READ_REQ *smb = NULL;
1595 int wct;
1596 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001597 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001598 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001599
Joe Perchesf96637b2013-05-04 22:12:25 -05001600 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1601 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602
1603 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1604 wct = 12;
1605 else {
1606 wct = 10; /* old style read */
1607 if ((rdata->offset >> 32) > 0) {
1608 /* can not handle this big offset for old */
1609 return -EIO;
1610 }
1611 }
1612
1613 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1614 if (rc)
1615 return rc;
1616
1617 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1618 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1619
1620 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001621 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001622 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1623 if (wct == 12)
1624 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1625 smb->Remaining = 0;
1626 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1627 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1628 if (wct == 12)
1629 smb->ByteCount = 0;
1630 else {
1631 /* old style read */
1632 struct smb_com_readx_req *smbr =
1633 (struct smb_com_readx_req *)smb;
1634 smbr->ByteCount = 0;
1635 }
1636
1637 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001638 rdata->iov.iov_base = smb;
1639 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001640
Jeff Layton6993f742012-05-16 07:13:17 -04001641 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001642 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1643 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001644
1645 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001646 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001647 else
1648 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001649
1650 cifs_small_buf_release(smb);
1651 return rc;
1652}
1653
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001655CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1656 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657{
1658 int rc = -EACCES;
1659 READ_REQ *pSMB = NULL;
1660 READ_RSP *pSMBr = NULL;
1661 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001662 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001663 int resp_buf_type = 0;
1664 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001665 __u32 pid = io_parms->pid;
1666 __u16 netfid = io_parms->netfid;
1667 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001668 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001669 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
Joe Perchesf96637b2013-05-04 22:12:25 -05001671 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001672 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001673 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001674 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001675 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001676 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001677 /* can not handle this big offset for old */
1678 return -EIO;
1679 }
1680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
1682 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001683 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 if (rc)
1685 return rc;
1686
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001687 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1688 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1689
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 /* tcon and ses pointer are checked in smb_init */
1691 if (tcon->ses->server == NULL)
1692 return -ECONNABORTED;
1693
Steve Frenchec637e32005-12-12 20:53:18 -08001694 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001696 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001697 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001698 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 pSMB->Remaining = 0;
1701 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1702 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001703 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001704 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1705 else {
1706 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001707 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001708 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001709 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001710 }
Steve Frenchec637e32005-12-12 20:53:18 -08001711
1712 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001713 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001714 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001715 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001716 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001717 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001719 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 } else {
1721 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1722 data_length = data_length << 16;
1723 data_length += le16_to_cpu(pSMBr->DataLength);
1724 *nbytes = data_length;
1725
1726 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001727 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001729 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001730 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 rc = -EIO;
1732 *nbytes = 0;
1733 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001734 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001735 le16_to_cpu(pSMBr->DataOffset);
1736/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001737 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001738 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001739 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001740 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001741 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 }
1743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
Steve French4b8f9302006-02-26 16:41:18 +00001745/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001746 if (*buf) {
1747 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001748 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001749 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001750 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001751 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001752 /* return buffer to caller to free */
1753 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001754 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001755 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001756 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001757 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001758 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001759
1760 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 since file handle passed in no longer valid */
1762 return rc;
1763}
1764
Steve Frenchec637e32005-12-12 20:53:18 -08001765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001767CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001768 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001769 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770{
1771 int rc = -EACCES;
1772 WRITE_REQ *pSMB = NULL;
1773 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001774 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 __u32 bytes_sent;
1776 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001777 __u32 pid = io_parms->pid;
1778 __u16 netfid = io_parms->netfid;
1779 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001780 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001781 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Steve Frencha24e2d72010-04-03 17:20:21 +00001783 *nbytes = 0;
1784
Joe Perchesf96637b2013-05-04 22:12:25 -05001785 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001786 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001787 return -ECONNABORTED;
1788
Steve French790fe572007-07-07 19:25:05 +00001789 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001790 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001791 else {
Steve French1c955182005-08-30 20:58:07 -07001792 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001793 if ((offset >> 32) > 0) {
1794 /* can not handle big offset for old srv */
1795 return -EIO;
1796 }
1797 }
Steve French1c955182005-08-30 20:58:07 -07001798
1799 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 (void **) &pSMBr);
1801 if (rc)
1802 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001803
1804 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1805 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 /* tcon and ses pointer are checked in smb_init */
1808 if (tcon->ses->server == NULL)
1809 return -ECONNABORTED;
1810
1811 pSMB->AndXCommand = 0xFF; /* none */
1812 pSMB->Fid = netfid;
1813 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001814 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001815 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001816
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 pSMB->Reserved = 0xFFFFFFFF;
1818 pSMB->WriteMode = 0;
1819 pSMB->Remaining = 0;
1820
Steve French50c2f752007-07-13 00:33:32 +00001821 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 can send more if LARGE_WRITE_X capability returned by the server and if
1823 our buffer is big enough or if we convert to iovecs on socket writes
1824 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001825 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1827 } else {
1828 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1829 & ~0xFF;
1830 }
1831
1832 if (bytes_sent > count)
1833 bytes_sent = count;
1834 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001835 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001836 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001837 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001838 else if (ubuf) {
1839 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 cifs_buf_release(pSMB);
1841 return -EFAULT;
1842 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001843 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* No buffer */
1845 cifs_buf_release(pSMB);
1846 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001847 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001848 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001849 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001850 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001851 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1854 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001855 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001856
Steve French790fe572007-07-07 19:25:05 +00001857 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001858 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001859 else { /* old style write has byte count 4 bytes earlier
1860 so 4 bytes pad */
1861 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001862 (struct smb_com_writex_req *)pSMB;
1863 pSMBW->ByteCount = cpu_to_le16(byte_count);
1864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1867 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001868 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001870 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 } else {
1872 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1873 *nbytes = (*nbytes) << 16;
1874 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301875
1876 /*
1877 * Mask off high 16 bits when bytes written as returned by the
1878 * server is greater than bytes requested by the client. Some
1879 * OS/2 servers are known to set incorrect CountHigh values.
1880 */
1881 if (*nbytes > count)
1882 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 }
1884
1885 cifs_buf_release(pSMB);
1886
Steve French50c2f752007-07-13 00:33:32 +00001887 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 since file handle passed in no longer valid */
1889
1890 return rc;
1891}
1892
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001893void
1894cifs_writedata_release(struct kref *refcount)
1895{
1896 struct cifs_writedata *wdata = container_of(refcount,
1897 struct cifs_writedata, refcount);
1898
1899 if (wdata->cfile)
1900 cifsFileInfo_put(wdata->cfile);
1901
1902 kfree(wdata);
1903}
1904
1905/*
1906 * Write failed with a retryable error. Resend the write request. It's also
1907 * possible that the page was redirtied so re-clean the page.
1908 */
1909static void
1910cifs_writev_requeue(struct cifs_writedata *wdata)
1911{
1912 int i, rc;
1913 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001914 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001915
1916 for (i = 0; i < wdata->nr_pages; i++) {
1917 lock_page(wdata->pages[i]);
1918 clear_page_dirty_for_io(wdata->pages[i]);
1919 }
1920
1921 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001922 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1923 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001924 } while (rc == -EAGAIN);
1925
1926 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001927 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001928 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001929 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001930 end_page_writeback(wdata->pages[i]);
1931 page_cache_release(wdata->pages[i]);
1932 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001933 }
1934
1935 mapping_set_error(inode->i_mapping, rc);
1936 kref_put(&wdata->refcount, cifs_writedata_release);
1937}
1938
Jeff Laytonc2e87642012-03-23 14:40:55 -04001939void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001940cifs_writev_complete(struct work_struct *work)
1941{
1942 struct cifs_writedata *wdata = container_of(work,
1943 struct cifs_writedata, work);
1944 struct inode *inode = wdata->cfile->dentry->d_inode;
1945 int i = 0;
1946
1947 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001948 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001949 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001950 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001951 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1952 wdata->bytes);
1953 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1954 return cifs_writev_requeue(wdata);
1955
1956 for (i = 0; i < wdata->nr_pages; i++) {
1957 struct page *page = wdata->pages[i];
1958 if (wdata->result == -EAGAIN)
1959 __set_page_dirty_nobuffers(page);
1960 else if (wdata->result < 0)
1961 SetPageError(page);
1962 end_page_writeback(page);
1963 page_cache_release(page);
1964 }
1965 if (wdata->result != -EAGAIN)
1966 mapping_set_error(inode->i_mapping, wdata->result);
1967 kref_put(&wdata->refcount, cifs_writedata_release);
1968}
1969
1970struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001971cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001972{
1973 struct cifs_writedata *wdata;
1974
1975 /* this would overflow */
1976 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001977 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001978 return NULL;
1979 }
1980
1981 /* writedata + number of page pointers */
1982 wdata = kzalloc(sizeof(*wdata) +
1983 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1984 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001985 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001986 INIT_LIST_HEAD(&wdata->list);
1987 init_completion(&wdata->done);
1988 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001989 }
1990 return wdata;
1991}
1992
1993/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001994 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001995 * workqueue completion task.
1996 */
1997static void
1998cifs_writev_callback(struct mid_q_entry *mid)
1999{
2000 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002001 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002002 unsigned int written;
2003 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2004
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002005 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002006 case MID_RESPONSE_RECEIVED:
2007 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2008 if (wdata->result != 0)
2009 break;
2010
2011 written = le16_to_cpu(smb->CountHigh);
2012 written <<= 16;
2013 written += le16_to_cpu(smb->Count);
2014 /*
2015 * Mask off high 16 bits when bytes written as returned
2016 * by the server is greater than bytes requested by the
2017 * client. OS/2 servers are known to set incorrect
2018 * CountHigh values.
2019 */
2020 if (written > wdata->bytes)
2021 written &= 0xFFFF;
2022
2023 if (written < wdata->bytes)
2024 wdata->result = -ENOSPC;
2025 else
2026 wdata->bytes = written;
2027 break;
2028 case MID_REQUEST_SUBMITTED:
2029 case MID_RETRY_NEEDED:
2030 wdata->result = -EAGAIN;
2031 break;
2032 default:
2033 wdata->result = -EIO;
2034 break;
2035 }
2036
Jeff Laytonda472fc2012-03-23 14:40:53 -04002037 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002038 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002039 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040}
2041
2042/* cifs_async_writev - send an async write, and set up mid to handle result */
2043int
2044cifs_async_writev(struct cifs_writedata *wdata)
2045{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002046 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002047 WRITE_REQ *smb = NULL;
2048 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002049 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002050 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002051 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052
2053 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2054 wct = 14;
2055 } else {
2056 wct = 12;
2057 if (wdata->offset >> 32 > 0) {
2058 /* can not handle big offset for old srv */
2059 return -EIO;
2060 }
2061 }
2062
2063 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2064 if (rc)
2065 goto async_writev_out;
2066
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002067 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2068 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002069
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002071 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002072 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2073 if (wct == 14)
2074 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2075 smb->Reserved = 0xFFFFFFFF;
2076 smb->WriteMode = 0;
2077 smb->Remaining = 0;
2078
2079 smb->DataOffset =
2080 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2081
2082 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002083 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2084 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002085
Jeff Laytoneddb0792012-09-18 16:20:35 -07002086 rqst.rq_iov = &iov;
2087 rqst.rq_nvec = 1;
2088 rqst.rq_pages = wdata->pages;
2089 rqst.rq_npages = wdata->nr_pages;
2090 rqst.rq_pagesz = wdata->pagesz;
2091 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002092
Joe Perchesf96637b2013-05-04 22:12:25 -05002093 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2094 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095
2096 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2097 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2098
2099 if (wct == 14) {
2100 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2101 put_bcc(wdata->bytes + 1, &smb->hdr);
2102 } else {
2103 /* wct == 12 */
2104 struct smb_com_writex_req *smbw =
2105 (struct smb_com_writex_req *)smb;
2106 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2107 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002108 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002109 }
2110
2111 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002112 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2113 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002114
2115 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002116 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002117 else
2118 kref_put(&wdata->refcount, cifs_writedata_release);
2119
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002120async_writev_out:
2121 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122 return rc;
2123}
2124
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002125int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002126CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002127 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128{
2129 int rc = -EACCES;
2130 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002131 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002132 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002133 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002134 __u32 pid = io_parms->pid;
2135 __u16 netfid = io_parms->netfid;
2136 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002137 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002138 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002140 *nbytes = 0;
2141
Joe Perchesf96637b2013-05-04 22:12:25 -05002142 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002143
Steve French4c3130e2008-12-09 00:28:16 +00002144 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002145 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002146 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002147 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002148 if ((offset >> 32) > 0) {
2149 /* can not handle big offset for old srv */
2150 return -EIO;
2151 }
2152 }
Steve French8cc64c62005-10-03 13:49:43 -07002153 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 if (rc)
2155 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002156
2157 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2158 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2159
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 /* tcon and ses pointer are checked in smb_init */
2161 if (tcon->ses->server == NULL)
2162 return -ECONNABORTED;
2163
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002164 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 pSMB->Fid = netfid;
2166 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002167 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002168 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 pSMB->Reserved = 0xFFFFFFFF;
2170 pSMB->WriteMode = 0;
2171 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002172
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002174 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
Steve French3e844692005-10-03 13:37:24 -07002176 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2177 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002178 /* header + 1 byte pad */
2179 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002180 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002181 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002182 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002183 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002184 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002185 pSMB->ByteCount = cpu_to_le16(count + 1);
2186 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002187 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002188 (struct smb_com_writex_req *)pSMB;
2189 pSMBW->ByteCount = cpu_to_le16(count + 5);
2190 }
Steve French3e844692005-10-03 13:37:24 -07002191 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002192 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002193 iov[0].iov_len = smb_hdr_len + 4;
2194 else /* wct == 12 pad bigger by four bytes */
2195 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002196
Steve French3e844692005-10-03 13:37:24 -07002197
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002198 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002199 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002201 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002202 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002203 /* presumably this can not happen, but best to be safe */
2204 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002205 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002206 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002207 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2208 *nbytes = (*nbytes) << 16;
2209 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302210
2211 /*
2212 * Mask off high 16 bits when bytes written as returned by the
2213 * server is greater than bytes requested by the client. OS/2
2214 * servers are known to set incorrect CountHigh values.
2215 */
2216 if (*nbytes > count)
2217 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Steve French4b8f9302006-02-26 16:41:18 +00002220/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002221 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002222 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002223 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002224 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Steve French50c2f752007-07-13 00:33:32 +00002226 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 since file handle passed in no longer valid */
2228
2229 return rc;
2230}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002231
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002232int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2233 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002234 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2235{
2236 int rc = 0;
2237 LOCK_REQ *pSMB = NULL;
2238 struct kvec iov[2];
2239 int resp_buf_type;
2240 __u16 count;
2241
Joe Perchesf96637b2013-05-04 22:12:25 -05002242 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2243 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002244
2245 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2246 if (rc)
2247 return rc;
2248
2249 pSMB->Timeout = 0;
2250 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2251 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2252 pSMB->LockType = lock_type;
2253 pSMB->AndXCommand = 0xFF; /* none */
2254 pSMB->Fid = netfid; /* netfid stays le */
2255
2256 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2257 inc_rfc1001_len(pSMB, count);
2258 pSMB->ByteCount = cpu_to_le16(count);
2259
2260 iov[0].iov_base = (char *)pSMB;
2261 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2262 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2263 iov[1].iov_base = (char *)buf;
2264 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2265
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002266 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002267 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2268 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002269 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002270
2271 return rc;
2272}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002273
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002275CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002276 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002278 const __u32 numLock, const __u8 lockType,
2279 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280{
2281 int rc = 0;
2282 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002283/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002285 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 __u16 count;
2287
Joe Perchesf96637b2013-05-04 22:12:25 -05002288 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2289 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002290 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2291
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 if (rc)
2293 return rc;
2294
Steve French790fe572007-07-07 19:25:05 +00002295 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002296 /* no response expected */
2297 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002299 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002300 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2302 } else {
2303 pSMB->Timeout = 0;
2304 }
2305
2306 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2307 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2308 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002309 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 pSMB->AndXCommand = 0xFF; /* none */
2311 pSMB->Fid = smb_file_id; /* netfid stays le */
2312
Steve French790fe572007-07-07 19:25:05 +00002313 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002314 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 /* BB where to store pid high? */
2316 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2317 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2318 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2319 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2320 count = sizeof(LOCKING_ANDX_RANGE);
2321 } else {
2322 /* oplock break */
2323 count = 0;
2324 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002325 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 pSMB->ByteCount = cpu_to_le16(count);
2327
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002328 if (waitFlag) {
2329 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002330 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002331 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002332 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002333 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002334 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002335 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002336 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002337 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002338 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
Steve French50c2f752007-07-13 00:33:32 +00002340 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 since file handle passed in no longer valid */
2342 return rc;
2343}
2344
2345int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002346CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002347 const __u16 smb_file_id, const __u32 netpid,
2348 const loff_t start_offset, const __u64 len,
2349 struct file_lock *pLockData, const __u16 lock_type,
2350 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002351{
2352 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2353 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002354 struct cifs_posix_lock *parm_data;
2355 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002356 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002357 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002358 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002359 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002360 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002361
Joe Perchesf96637b2013-05-04 22:12:25 -05002362 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002363
Steve French08547b02006-02-28 22:39:25 +00002364 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2365
2366 if (rc)
2367 return rc;
2368
2369 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2370
Steve French50c2f752007-07-13 00:33:32 +00002371 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002372 pSMB->MaxSetupCount = 0;
2373 pSMB->Reserved = 0;
2374 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002375 pSMB->Reserved2 = 0;
2376 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2377 offset = param_offset + params;
2378
Steve French08547b02006-02-28 22:39:25 +00002379 count = sizeof(struct cifs_posix_lock);
2380 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002381 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002382 pSMB->SetupCount = 1;
2383 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002384 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2386 else
2387 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2388 byte_count = 3 /* pad */ + params + count;
2389 pSMB->DataCount = cpu_to_le16(count);
2390 pSMB->ParameterCount = cpu_to_le16(params);
2391 pSMB->TotalDataCount = pSMB->DataCount;
2392 pSMB->TotalParameterCount = pSMB->ParameterCount;
2393 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002394 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002395 (((char *) &pSMB->hdr.Protocol) + offset);
2396
2397 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002398 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002399 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002400 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002401 pSMB->Timeout = cpu_to_le32(-1);
2402 } else
2403 pSMB->Timeout = 0;
2404
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002405 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002406 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002407 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002408
2409 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002410 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002411 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2412 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002413 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002414 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002415 if (waitFlag) {
2416 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2417 (struct smb_hdr *) pSMBr, &bytes_returned);
2418 } else {
Steve French133672e2007-11-13 22:41:37 +00002419 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002420 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002421 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2422 &resp_buf_type, timeout);
2423 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2424 not try to free it twice below on exit */
2425 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002426 }
2427
Steve French08547b02006-02-28 22:39:25 +00002428 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002429 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002430 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002431 /* lock structure can be returned on get */
2432 __u16 data_offset;
2433 __u16 data_count;
2434 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002435
Jeff Layton820a8032011-05-04 08:05:26 -04002436 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002437 rc = -EIO; /* bad smb */
2438 goto plk_err_exit;
2439 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002440 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2441 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002442 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002443 rc = -EIO;
2444 goto plk_err_exit;
2445 }
2446 parm_data = (struct cifs_posix_lock *)
2447 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002448 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002449 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002450 else {
2451 if (parm_data->lock_type ==
2452 __constant_cpu_to_le16(CIFS_RDLCK))
2453 pLockData->fl_type = F_RDLCK;
2454 else if (parm_data->lock_type ==
2455 __constant_cpu_to_le16(CIFS_WRLCK))
2456 pLockData->fl_type = F_WRLCK;
2457
Steve French5443d132011-03-13 05:08:25 +00002458 pLockData->fl_start = le64_to_cpu(parm_data->start);
2459 pLockData->fl_end = pLockData->fl_start +
2460 le64_to_cpu(parm_data->length) - 1;
2461 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002462 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002463 }
Steve French50c2f752007-07-13 00:33:32 +00002464
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002465plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002466 if (pSMB)
2467 cifs_small_buf_release(pSMB);
2468
Steve French133672e2007-11-13 22:41:37 +00002469 if (resp_buf_type == CIFS_SMALL_BUFFER)
2470 cifs_small_buf_release(iov[0].iov_base);
2471 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2472 cifs_buf_release(iov[0].iov_base);
2473
Steve French08547b02006-02-28 22:39:25 +00002474 /* Note: On -EAGAIN error only caller can retry on handle based calls
2475 since file handle passed in no longer valid */
2476
2477 return rc;
2478}
2479
2480
2481int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002482CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483{
2484 int rc = 0;
2485 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002486 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488/* do not retry on dead session on close */
2489 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002490 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 return 0;
2492 if (rc)
2493 return rc;
2494
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002496 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002498 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002499 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002501 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002503 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 }
2505 }
2506
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002508 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 rc = 0;
2510
2511 return rc;
2512}
2513
2514int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002515CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002516{
2517 int rc = 0;
2518 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002519 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002520
2521 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2522 if (rc)
2523 return rc;
2524
2525 pSMB->FileID = (__u16) smb_file_id;
2526 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002527 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002528 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002529 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002530 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002531
2532 return rc;
2533}
2534
2535int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002536CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002537 const char *from_name, const char *to_name,
2538 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539{
2540 int rc = 0;
2541 RENAME_REQ *pSMB = NULL;
2542 RENAME_RSP *pSMBr = NULL;
2543 int bytes_returned;
2544 int name_len, name_len2;
2545 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002546 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
Joe Perchesf96637b2013-05-04 22:12:25 -05002548 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549renameRetry:
2550 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2551 (void **) &pSMBr);
2552 if (rc)
2553 return rc;
2554
2555 pSMB->BufferFormat = 0x04;
2556 pSMB->SearchAttributes =
2557 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2558 ATTR_DIRECTORY);
2559
2560 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002561 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2562 from_name, PATH_MAX,
2563 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 name_len++; /* trailing null */
2565 name_len *= 2;
2566 pSMB->OldFileName[name_len] = 0x04; /* pad */
2567 /* protocol requires ASCII signature byte on Unicode string */
2568 pSMB->OldFileName[name_len + 1] = 0x00;
2569 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002570 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002571 to_name, PATH_MAX, cifs_sb->local_nls,
2572 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2574 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002575 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002576 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002578 strncpy(pSMB->OldFileName, from_name, name_len);
2579 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 name_len2++; /* trailing null */
2581 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002582 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 name_len2++; /* trailing null */
2584 name_len2++; /* signature byte */
2585 }
2586
2587 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002588 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 pSMB->ByteCount = cpu_to_le16(count);
2590
2591 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2592 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002593 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002594 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002595 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 cifs_buf_release(pSMB);
2598
2599 if (rc == -EAGAIN)
2600 goto renameRetry;
2601
2602 return rc;
2603}
2604
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002605int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002606 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002607 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
2609 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2610 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002611 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 char *data_offset;
2613 char dummy_string[30];
2614 int rc = 0;
2615 int bytes_returned = 0;
2616 int len_of_str;
2617 __u16 params, param_offset, offset, count, byte_count;
2618
Joe Perchesf96637b2013-05-04 22:12:25 -05002619 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2621 (void **) &pSMBr);
2622 if (rc)
2623 return rc;
2624
2625 params = 6;
2626 pSMB->MaxSetupCount = 0;
2627 pSMB->Reserved = 0;
2628 pSMB->Flags = 0;
2629 pSMB->Timeout = 0;
2630 pSMB->Reserved2 = 0;
2631 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2632 offset = param_offset + params;
2633
2634 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2635 rename_info = (struct set_file_rename *) data_offset;
2636 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002637 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 pSMB->SetupCount = 1;
2639 pSMB->Reserved3 = 0;
2640 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2641 byte_count = 3 /* pad */ + params;
2642 pSMB->ParameterCount = cpu_to_le16(params);
2643 pSMB->TotalParameterCount = pSMB->ParameterCount;
2644 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2645 pSMB->DataOffset = cpu_to_le16(offset);
2646 /* construct random name ".cifs_tmp<inodenum><mid>" */
2647 rename_info->overwrite = cpu_to_le32(1);
2648 rename_info->root_fid = 0;
2649 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002650 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002651 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002652 len_of_str =
2653 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002654 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002656 len_of_str =
2657 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002658 target_name, PATH_MAX, nls_codepage,
2659 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
2661 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002662 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 byte_count += count;
2664 pSMB->DataCount = cpu_to_le16(count);
2665 pSMB->TotalDataCount = pSMB->DataCount;
2666 pSMB->Fid = netfid;
2667 pSMB->InformationLevel =
2668 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2669 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002670 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 pSMB->ByteCount = cpu_to_le16(byte_count);
2672 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002673 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002674 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002675 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002676 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2677 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 cifs_buf_release(pSMB);
2680
2681 /* Note: On -EAGAIN error only caller can retry on handle based calls
2682 since file handle passed in no longer valid */
2683
2684 return rc;
2685}
2686
2687int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002688CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2689 const char *fromName, const __u16 target_tid, const char *toName,
2690 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691{
2692 int rc = 0;
2693 COPY_REQ *pSMB = NULL;
2694 COPY_RSP *pSMBr = NULL;
2695 int bytes_returned;
2696 int name_len, name_len2;
2697 __u16 count;
2698
Joe Perchesf96637b2013-05-04 22:12:25 -05002699 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700copyRetry:
2701 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2702 (void **) &pSMBr);
2703 if (rc)
2704 return rc;
2705
2706 pSMB->BufferFormat = 0x04;
2707 pSMB->Tid2 = target_tid;
2708
2709 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2710
2711 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002712 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2713 fromName, PATH_MAX, nls_codepage,
2714 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 name_len++; /* trailing null */
2716 name_len *= 2;
2717 pSMB->OldFileName[name_len] = 0x04; /* pad */
2718 /* protocol requires ASCII signature byte on Unicode string */
2719 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002720 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002721 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2722 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2724 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002725 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 name_len = strnlen(fromName, PATH_MAX);
2727 name_len++; /* trailing null */
2728 strncpy(pSMB->OldFileName, fromName, name_len);
2729 name_len2 = strnlen(toName, PATH_MAX);
2730 name_len2++; /* trailing null */
2731 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2732 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2733 name_len2++; /* trailing null */
2734 name_len2++; /* signature byte */
2735 }
2736
2737 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002738 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 pSMB->ByteCount = cpu_to_le16(count);
2740
2741 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2742 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2743 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002744 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2745 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 }
Steve French0d817bc2008-05-22 02:02:03 +00002747 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
2749 if (rc == -EAGAIN)
2750 goto copyRetry;
2751
2752 return rc;
2753}
2754
2755int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002756CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 const char *fromName, const char *toName,
2758 const struct nls_table *nls_codepage)
2759{
2760 TRANSACTION2_SPI_REQ *pSMB = NULL;
2761 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2762 char *data_offset;
2763 int name_len;
2764 int name_len_target;
2765 int rc = 0;
2766 int bytes_returned = 0;
2767 __u16 params, param_offset, offset, byte_count;
2768
Joe Perchesf96637b2013-05-04 22:12:25 -05002769 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770createSymLinkRetry:
2771 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2772 (void **) &pSMBr);
2773 if (rc)
2774 return rc;
2775
2776 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2777 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002778 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2779 /* find define for this maxpathcomponent */
2780 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 name_len++; /* trailing null */
2782 name_len *= 2;
2783
Steve French50c2f752007-07-13 00:33:32 +00002784 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 name_len = strnlen(fromName, PATH_MAX);
2786 name_len++; /* trailing null */
2787 strncpy(pSMB->FileName, fromName, name_len);
2788 }
2789 params = 6 + name_len;
2790 pSMB->MaxSetupCount = 0;
2791 pSMB->Reserved = 0;
2792 pSMB->Flags = 0;
2793 pSMB->Timeout = 0;
2794 pSMB->Reserved2 = 0;
2795 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002796 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 offset = param_offset + params;
2798
2799 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2800 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2801 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002802 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2803 /* find define for this maxpathcomponent */
2804 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 name_len_target++; /* trailing null */
2806 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002807 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 name_len_target = strnlen(toName, PATH_MAX);
2809 name_len_target++; /* trailing null */
2810 strncpy(data_offset, toName, name_len_target);
2811 }
2812
2813 pSMB->MaxParameterCount = cpu_to_le16(2);
2814 /* BB find exact max on data count below from sess */
2815 pSMB->MaxDataCount = cpu_to_le16(1000);
2816 pSMB->SetupCount = 1;
2817 pSMB->Reserved3 = 0;
2818 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2819 byte_count = 3 /* pad */ + params + name_len_target;
2820 pSMB->DataCount = cpu_to_le16(name_len_target);
2821 pSMB->ParameterCount = cpu_to_le16(params);
2822 pSMB->TotalDataCount = pSMB->DataCount;
2823 pSMB->TotalParameterCount = pSMB->ParameterCount;
2824 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2825 pSMB->DataOffset = cpu_to_le16(offset);
2826 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2827 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002828 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 pSMB->ByteCount = cpu_to_le16(byte_count);
2830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002832 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002833 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002834 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2835 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836
Steve French0d817bc2008-05-22 02:02:03 +00002837 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
2839 if (rc == -EAGAIN)
2840 goto createSymLinkRetry;
2841
2842 return rc;
2843}
2844
2845int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002846CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002848 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849{
2850 TRANSACTION2_SPI_REQ *pSMB = NULL;
2851 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2852 char *data_offset;
2853 int name_len;
2854 int name_len_target;
2855 int rc = 0;
2856 int bytes_returned = 0;
2857 __u16 params, param_offset, offset, byte_count;
2858
Joe Perchesf96637b2013-05-04 22:12:25 -05002859 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860createHardLinkRetry:
2861 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2862 (void **) &pSMBr);
2863 if (rc)
2864 return rc;
2865
2866 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002867 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2868 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 name_len++; /* trailing null */
2870 name_len *= 2;
2871
Steve French50c2f752007-07-13 00:33:32 +00002872 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 name_len = strnlen(toName, PATH_MAX);
2874 name_len++; /* trailing null */
2875 strncpy(pSMB->FileName, toName, name_len);
2876 }
2877 params = 6 + name_len;
2878 pSMB->MaxSetupCount = 0;
2879 pSMB->Reserved = 0;
2880 pSMB->Flags = 0;
2881 pSMB->Timeout = 0;
2882 pSMB->Reserved2 = 0;
2883 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002884 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 offset = param_offset + params;
2886
2887 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2888 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2889 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002890 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2891 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 name_len_target++; /* trailing null */
2893 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002894 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 name_len_target = strnlen(fromName, PATH_MAX);
2896 name_len_target++; /* trailing null */
2897 strncpy(data_offset, fromName, name_len_target);
2898 }
2899
2900 pSMB->MaxParameterCount = cpu_to_le16(2);
2901 /* BB find exact max on data count below from sess*/
2902 pSMB->MaxDataCount = cpu_to_le16(1000);
2903 pSMB->SetupCount = 1;
2904 pSMB->Reserved3 = 0;
2905 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2906 byte_count = 3 /* pad */ + params + name_len_target;
2907 pSMB->ParameterCount = cpu_to_le16(params);
2908 pSMB->TotalParameterCount = pSMB->ParameterCount;
2909 pSMB->DataCount = cpu_to_le16(name_len_target);
2910 pSMB->TotalDataCount = pSMB->DataCount;
2911 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2912 pSMB->DataOffset = cpu_to_le16(offset);
2913 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2914 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002915 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 pSMB->ByteCount = cpu_to_le16(byte_count);
2917 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2918 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002919 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002920 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002921 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2922 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
2924 cifs_buf_release(pSMB);
2925 if (rc == -EAGAIN)
2926 goto createHardLinkRetry;
2927
2928 return rc;
2929}
2930
2931int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002932CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002933 const char *from_name, const char *to_name,
2934 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935{
2936 int rc = 0;
2937 NT_RENAME_REQ *pSMB = NULL;
2938 RENAME_RSP *pSMBr = NULL;
2939 int bytes_returned;
2940 int name_len, name_len2;
2941 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002942 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
Joe Perchesf96637b2013-05-04 22:12:25 -05002944 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945winCreateHardLinkRetry:
2946
2947 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2948 (void **) &pSMBr);
2949 if (rc)
2950 return rc;
2951
2952 pSMB->SearchAttributes =
2953 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2954 ATTR_DIRECTORY);
2955 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2956 pSMB->ClusterCount = 0;
2957
2958 pSMB->BufferFormat = 0x04;
2959
2960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2961 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002962 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2963 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len++; /* trailing null */
2965 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002966
2967 /* protocol specifies ASCII buffer format (0x04) for unicode */
2968 pSMB->OldFileName[name_len] = 0x04;
2969 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002971 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002972 to_name, PATH_MAX, cifs_sb->local_nls,
2973 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2975 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002976 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002977 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002979 strncpy(pSMB->OldFileName, from_name, name_len);
2980 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 name_len2++; /* trailing null */
2982 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002983 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 name_len2++; /* trailing null */
2985 name_len2++; /* signature byte */
2986 }
2987
2988 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002989 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 pSMB->ByteCount = cpu_to_le16(count);
2991
2992 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2993 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002994 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002995 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002996 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002997
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 cifs_buf_release(pSMB);
2999 if (rc == -EAGAIN)
3000 goto winCreateHardLinkRetry;
3001
3002 return rc;
3003}
3004
3005int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003006CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003007 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 const struct nls_table *nls_codepage)
3009{
3010/* SMB_QUERY_FILE_UNIX_LINK */
3011 TRANSACTION2_QPI_REQ *pSMB = NULL;
3012 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3013 int rc = 0;
3014 int bytes_returned;
3015 int name_len;
3016 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003017 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Joe Perchesf96637b2013-05-04 22:12:25 -05003019 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
3021querySymLinkRetry:
3022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3023 (void **) &pSMBr);
3024 if (rc)
3025 return rc;
3026
3027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3028 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003029 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3030 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 name_len++; /* trailing null */
3032 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003033 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 name_len = strnlen(searchName, PATH_MAX);
3035 name_len++; /* trailing null */
3036 strncpy(pSMB->FileName, searchName, name_len);
3037 }
3038
3039 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3040 pSMB->TotalDataCount = 0;
3041 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003042 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 pSMB->MaxSetupCount = 0;
3044 pSMB->Reserved = 0;
3045 pSMB->Flags = 0;
3046 pSMB->Timeout = 0;
3047 pSMB->Reserved2 = 0;
3048 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003049 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 pSMB->DataCount = 0;
3051 pSMB->DataOffset = 0;
3052 pSMB->SetupCount = 1;
3053 pSMB->Reserved3 = 0;
3054 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3055 byte_count = params + 1 /* pad */ ;
3056 pSMB->TotalParameterCount = cpu_to_le16(params);
3057 pSMB->ParameterCount = pSMB->TotalParameterCount;
3058 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3059 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003060 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 pSMB->ByteCount = cpu_to_le16(byte_count);
3062
3063 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3064 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3065 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003066 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 } else {
3068 /* decode response */
3069
3070 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003072 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003073 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003075 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003076 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
Jeff Layton460b9692009-04-30 07:17:56 -04003078 data_start = ((char *) &pSMBr->hdr.Protocol) +
3079 le16_to_cpu(pSMBr->t2.DataOffset);
3080
Steve French0e0d2cf2009-05-01 05:27:32 +00003081 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3082 is_unicode = true;
3083 else
3084 is_unicode = false;
3085
Steve French737b7582005-04-28 22:41:06 -07003086 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003087 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3088 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003089 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003090 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 }
3092 }
3093 cifs_buf_release(pSMB);
3094 if (rc == -EAGAIN)
3095 goto querySymLinkRetry;
3096 return rc;
3097}
3098
Steve Frenchc52a95542011-02-24 06:16:22 +00003099#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3100/*
3101 * Recent Windows versions now create symlinks more frequently
3102 * and they use the "reparse point" mechanism below. We can of course
3103 * do symlinks nicely to Samba and other servers which support the
3104 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3105 * "MF" symlinks optionally, but for recent Windows we really need to
3106 * reenable the code below and fix the cifs_symlink callers to handle this.
3107 * In the interim this code has been moved to its own config option so
3108 * it is not compiled in by default until callers fixed up and more tested.
3109 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003111CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003113 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 const struct nls_table *nls_codepage)
3115{
3116 int rc = 0;
3117 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003118 struct smb_com_transaction_ioctl_req *pSMB;
3119 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
Joe Perchesf96637b2013-05-04 22:12:25 -05003121 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3122 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3124 (void **) &pSMBr);
3125 if (rc)
3126 return rc;
3127
3128 pSMB->TotalParameterCount = 0 ;
3129 pSMB->TotalDataCount = 0;
3130 pSMB->MaxParameterCount = cpu_to_le32(2);
3131 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003132 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 pSMB->MaxSetupCount = 4;
3134 pSMB->Reserved = 0;
3135 pSMB->ParameterOffset = 0;
3136 pSMB->DataCount = 0;
3137 pSMB->DataOffset = 0;
3138 pSMB->SetupCount = 4;
3139 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3140 pSMB->ParameterCount = pSMB->TotalParameterCount;
3141 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3142 pSMB->IsFsctl = 1; /* FSCTL */
3143 pSMB->IsRootFlag = 0;
3144 pSMB->Fid = fid; /* file handle always le */
3145 pSMB->ByteCount = 0;
3146
3147 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3148 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3149 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003150 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 } else { /* decode response */
3152 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3153 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003154 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3155 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003157 goto qreparse_out;
3158 }
3159 if (data_count && (data_count < 2048)) {
3160 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003161 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
Steve Frenchafe48c32009-05-02 05:25:46 +00003163 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003164 (struct reparse_data *)
3165 ((char *)&pSMBr->hdr.Protocol
3166 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003167 if ((char *)reparse_buf >= end_of_smb) {
3168 rc = -EIO;
3169 goto qreparse_out;
3170 }
3171 if ((reparse_buf->LinkNamesBuf +
3172 reparse_buf->TargetNameOffset +
3173 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003174 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003175 rc = -EIO;
3176 goto qreparse_out;
3177 }
Steve French50c2f752007-07-13 00:33:32 +00003178
Steve Frenchafe48c32009-05-02 05:25:46 +00003179 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3180 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003181 (reparse_buf->LinkNamesBuf +
3182 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003183 buflen,
3184 reparse_buf->TargetNameLen,
3185 nls_codepage, 0);
3186 } else { /* ASCII names */
3187 strncpy(symlinkinfo,
3188 reparse_buf->LinkNamesBuf +
3189 reparse_buf->TargetNameOffset,
3190 min_t(const int, buflen,
3191 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003193 } else {
3194 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003195 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003197 symlinkinfo[buflen] = 0; /* just in case so the caller
3198 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003199 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 }
Steve French989c7e52009-05-02 05:32:20 +00003201
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003203 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
3205 /* Note: On -EAGAIN error only caller can retry on handle based calls
3206 since file handle passed in no longer valid */
3207
3208 return rc;
3209}
Steve Frenchc52a95542011-02-24 06:16:22 +00003210#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
3212#ifdef CONFIG_CIFS_POSIX
3213
3214/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003215static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3216 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217{
3218 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003219 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3220 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3221 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003222/*
3223 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3224 ace->e_perm, ace->e_tag, ace->e_id);
3225*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226
3227 return;
3228}
3229
3230/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003231static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3232 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
3234 int size = 0;
3235 int i;
3236 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003237 struct cifs_posix_ace *pACE;
3238 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3239 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
3241 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3242 return -EOPNOTSUPP;
3243
Steve French790fe572007-07-07 19:25:05 +00003244 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 count = le16_to_cpu(cifs_acl->access_entry_count);
3246 pACE = &cifs_acl->ace_array[0];
3247 size = sizeof(struct cifs_posix_acl);
3248 size += sizeof(struct cifs_posix_ace) * count;
3249 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003250 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003251 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3252 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 return -EINVAL;
3254 }
Steve French790fe572007-07-07 19:25:05 +00003255 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 count = le16_to_cpu(cifs_acl->access_entry_count);
3257 size = sizeof(struct cifs_posix_acl);
3258 size += sizeof(struct cifs_posix_ace) * count;
3259/* skip past access ACEs to get to default ACEs */
3260 pACE = &cifs_acl->ace_array[count];
3261 count = le16_to_cpu(cifs_acl->default_entry_count);
3262 size += sizeof(struct cifs_posix_ace) * count;
3263 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003264 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 return -EINVAL;
3266 } else {
3267 /* illegal type */
3268 return -EINVAL;
3269 }
3270
3271 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003272 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003273 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003274 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 return -ERANGE;
3276 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003277 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003278 for (i = 0; i < count ; i++) {
3279 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3280 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 }
3282 }
3283 return size;
3284}
3285
Steve French50c2f752007-07-13 00:33:32 +00003286static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3287 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288{
3289 __u16 rc = 0; /* 0 = ACL converted ok */
3290
Steve Frenchff7feac2005-11-15 16:45:16 -08003291 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3292 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003294 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 /* Probably no need to le convert -1 on any arch but can not hurt */
3296 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003297 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003298 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003299/*
3300 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3301 ace->e_perm, ace->e_tag, ace->e_id);
3302*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 return rc;
3304}
3305
3306/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003307static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3308 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309{
3310 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003311 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3312 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 int count;
3314 int i;
3315
Steve French790fe572007-07-07 19:25:05 +00003316 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 return 0;
3318
3319 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003320 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3321 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003322 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003323 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3324 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 return 0;
3326 }
3327 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003328 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003329 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003330 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003331 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003333 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 return 0;
3335 }
Steve French50c2f752007-07-13 00:33:32 +00003336 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3338 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003339 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 /* ACE not converted */
3341 break;
3342 }
3343 }
Steve French790fe572007-07-07 19:25:05 +00003344 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3346 rc += sizeof(struct cifs_posix_acl);
3347 /* BB add check to make sure ACL does not overflow SMB */
3348 }
3349 return rc;
3350}
3351
3352int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003353CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003354 const unsigned char *searchName,
3355 char *acl_inf, const int buflen, const int acl_type,
3356 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357{
3358/* SMB_QUERY_POSIX_ACL */
3359 TRANSACTION2_QPI_REQ *pSMB = NULL;
3360 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3361 int rc = 0;
3362 int bytes_returned;
3363 int name_len;
3364 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003365
Joe Perchesf96637b2013-05-04 22:12:25 -05003366 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367
3368queryAclRetry:
3369 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3370 (void **) &pSMBr);
3371 if (rc)
3372 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003373
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3375 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003376 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3377 searchName, PATH_MAX, nls_codepage,
3378 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 name_len++; /* trailing null */
3380 name_len *= 2;
3381 pSMB->FileName[name_len] = 0;
3382 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003383 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 name_len = strnlen(searchName, PATH_MAX);
3385 name_len++; /* trailing null */
3386 strncpy(pSMB->FileName, searchName, name_len);
3387 }
3388
3389 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3390 pSMB->TotalDataCount = 0;
3391 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003392 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 pSMB->MaxDataCount = cpu_to_le16(4000);
3394 pSMB->MaxSetupCount = 0;
3395 pSMB->Reserved = 0;
3396 pSMB->Flags = 0;
3397 pSMB->Timeout = 0;
3398 pSMB->Reserved2 = 0;
3399 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003400 offsetof(struct smb_com_transaction2_qpi_req,
3401 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 pSMB->DataCount = 0;
3403 pSMB->DataOffset = 0;
3404 pSMB->SetupCount = 1;
3405 pSMB->Reserved3 = 0;
3406 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3407 byte_count = params + 1 /* pad */ ;
3408 pSMB->TotalParameterCount = cpu_to_le16(params);
3409 pSMB->ParameterCount = pSMB->TotalParameterCount;
3410 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3411 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003412 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 pSMB->ByteCount = cpu_to_le16(byte_count);
3414
3415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003417 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003419 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 } else {
3421 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003422
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003425 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 rc = -EIO; /* bad smb */
3427 else {
3428 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3429 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3430 rc = cifs_copy_posix_acl(acl_inf,
3431 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003432 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 }
3434 }
3435 cifs_buf_release(pSMB);
3436 if (rc == -EAGAIN)
3437 goto queryAclRetry;
3438 return rc;
3439}
3440
3441int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003442CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003443 const unsigned char *fileName,
3444 const char *local_acl, const int buflen,
3445 const int acl_type,
3446 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447{
3448 struct smb_com_transaction2_spi_req *pSMB = NULL;
3449 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3450 char *parm_data;
3451 int name_len;
3452 int rc = 0;
3453 int bytes_returned = 0;
3454 __u16 params, byte_count, data_count, param_offset, offset;
3455
Joe Perchesf96637b2013-05-04 22:12:25 -05003456 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457setAclRetry:
3458 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003459 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 if (rc)
3461 return rc;
3462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3463 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003464 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3465 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 name_len++; /* trailing null */
3467 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003468 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 name_len = strnlen(fileName, PATH_MAX);
3470 name_len++; /* trailing null */
3471 strncpy(pSMB->FileName, fileName, name_len);
3472 }
3473 params = 6 + name_len;
3474 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003475 /* BB find max SMB size from sess */
3476 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 pSMB->MaxSetupCount = 0;
3478 pSMB->Reserved = 0;
3479 pSMB->Flags = 0;
3480 pSMB->Timeout = 0;
3481 pSMB->Reserved2 = 0;
3482 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003483 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 offset = param_offset + params;
3485 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3486 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3487
3488 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003489 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Steve French790fe572007-07-07 19:25:05 +00003491 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 rc = -EOPNOTSUPP;
3493 goto setACLerrorExit;
3494 }
3495 pSMB->DataOffset = cpu_to_le16(offset);
3496 pSMB->SetupCount = 1;
3497 pSMB->Reserved3 = 0;
3498 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3499 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3500 byte_count = 3 /* pad */ + params + data_count;
3501 pSMB->DataCount = cpu_to_le16(data_count);
3502 pSMB->TotalDataCount = pSMB->DataCount;
3503 pSMB->ParameterCount = cpu_to_le16(params);
3504 pSMB->TotalParameterCount = pSMB->ParameterCount;
3505 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003506 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 pSMB->ByteCount = cpu_to_le16(byte_count);
3508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003510 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003511 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
3513setACLerrorExit:
3514 cifs_buf_release(pSMB);
3515 if (rc == -EAGAIN)
3516 goto setAclRetry;
3517 return rc;
3518}
3519
Steve Frenchf654bac2005-04-28 22:41:04 -07003520/* BB fix tabs in this function FIXME BB */
3521int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003522CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003523 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003524{
Steve French50c2f752007-07-13 00:33:32 +00003525 int rc = 0;
3526 struct smb_t2_qfi_req *pSMB = NULL;
3527 struct smb_t2_qfi_rsp *pSMBr = NULL;
3528 int bytes_returned;
3529 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003530
Joe Perchesf96637b2013-05-04 22:12:25 -05003531 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003532 if (tcon == NULL)
3533 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003534
3535GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003536 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3537 (void **) &pSMBr);
3538 if (rc)
3539 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003540
Steve Frenchad7a2922008-02-07 23:25:02 +00003541 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003542 pSMB->t2.TotalDataCount = 0;
3543 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3544 /* BB find exact max data count below from sess structure BB */
3545 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3546 pSMB->t2.MaxSetupCount = 0;
3547 pSMB->t2.Reserved = 0;
3548 pSMB->t2.Flags = 0;
3549 pSMB->t2.Timeout = 0;
3550 pSMB->t2.Reserved2 = 0;
3551 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3552 Fid) - 4);
3553 pSMB->t2.DataCount = 0;
3554 pSMB->t2.DataOffset = 0;
3555 pSMB->t2.SetupCount = 1;
3556 pSMB->t2.Reserved3 = 0;
3557 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3558 byte_count = params + 1 /* pad */ ;
3559 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3560 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3561 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3562 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003563 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003564 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003565 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003566
Steve French790fe572007-07-07 19:25:05 +00003567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3569 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003570 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003571 } else {
3572 /* decode response */
3573 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003574 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003575 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003576 /* If rc should we check for EOPNOSUPP and
3577 disable the srvino flag? or in caller? */
3578 rc = -EIO; /* bad smb */
3579 else {
3580 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3581 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3582 struct file_chattr_info *pfinfo;
3583 /* BB Do we need a cast or hash here ? */
3584 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003585 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003586 rc = -EIO;
3587 goto GetExtAttrOut;
3588 }
3589 pfinfo = (struct file_chattr_info *)
3590 (data_offset + (char *) &pSMBr->hdr.Protocol);
3591 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003592 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003593 }
3594 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003595GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003596 cifs_buf_release(pSMB);
3597 if (rc == -EAGAIN)
3598 goto GetExtAttrRetry;
3599 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003600}
3601
Steve Frenchf654bac2005-04-28 22:41:04 -07003602#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
Jeff Layton79df1ba2010-12-06 12:52:08 -05003604#ifdef CONFIG_CIFS_ACL
3605/*
3606 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3607 * all NT TRANSACTS that we init here have total parm and data under about 400
3608 * bytes (to fit in small cifs buffer size), which is the case so far, it
3609 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3610 * returned setup area) and MaxParameterCount (returned parms size) must be set
3611 * by caller
3612 */
3613static int
3614smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003615 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003616 void **ret_buf)
3617{
3618 int rc;
3619 __u32 temp_offset;
3620 struct smb_com_ntransact_req *pSMB;
3621
3622 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3623 (void **)&pSMB);
3624 if (rc)
3625 return rc;
3626 *ret_buf = (void *)pSMB;
3627 pSMB->Reserved = 0;
3628 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3629 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003630 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003631 pSMB->ParameterCount = pSMB->TotalParameterCount;
3632 pSMB->DataCount = pSMB->TotalDataCount;
3633 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3634 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3635 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3636 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3637 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3638 pSMB->SubCommand = cpu_to_le16(sub_command);
3639 return 0;
3640}
3641
3642static int
3643validate_ntransact(char *buf, char **ppparm, char **ppdata,
3644 __u32 *pparmlen, __u32 *pdatalen)
3645{
3646 char *end_of_smb;
3647 __u32 data_count, data_offset, parm_count, parm_offset;
3648 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003649 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003650
3651 *pdatalen = 0;
3652 *pparmlen = 0;
3653
3654 if (buf == NULL)
3655 return -EINVAL;
3656
3657 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3658
Jeff Layton820a8032011-05-04 08:05:26 -04003659 bcc = get_bcc(&pSMBr->hdr);
3660 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003661 (char *)&pSMBr->ByteCount;
3662
3663 data_offset = le32_to_cpu(pSMBr->DataOffset);
3664 data_count = le32_to_cpu(pSMBr->DataCount);
3665 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3666 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3667
3668 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3669 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3670
3671 /* should we also check that parm and data areas do not overlap? */
3672 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003673 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003674 return -EINVAL;
3675 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003676 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003677 return -EINVAL;
3678 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003679 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003680 return -EINVAL;
3681 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003682 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3683 *ppdata, data_count, (data_count + *ppdata),
3684 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003685 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003686 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003687 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003688 return -EINVAL;
3689 }
3690 *pdatalen = data_count;
3691 *pparmlen = parm_count;
3692 return 0;
3693}
3694
Steve French0a4b92c2006-01-12 15:44:21 -08003695/* Get Security Descriptor (by handle) from remote server for a file or dir */
3696int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003697CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003698 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003699{
3700 int rc = 0;
3701 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003702 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003703 struct kvec iov[1];
3704
Joe Perchesf96637b2013-05-04 22:12:25 -05003705 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003706
Steve French630f3f0c2007-10-25 21:17:17 +00003707 *pbuflen = 0;
3708 *acl_inf = NULL;
3709
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003710 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003711 8 /* parm len */, tcon, (void **) &pSMB);
3712 if (rc)
3713 return rc;
3714
3715 pSMB->MaxParameterCount = cpu_to_le32(4);
3716 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3717 pSMB->MaxSetupCount = 0;
3718 pSMB->Fid = fid; /* file handle always le */
3719 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3720 CIFS_ACL_DACL);
3721 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003722 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003723 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003724 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003725
Steve Frencha761ac52007-10-18 21:45:27 +00003726 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003727 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003728 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003729 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003730 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003731 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003732 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003733 __u32 parm_len;
3734 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003735 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003736 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003737
3738/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003739 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003740 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003741 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003742 goto qsec_out;
3743 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3744
Joe Perchesf96637b2013-05-04 22:12:25 -05003745 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3746 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003747
3748 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3749 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003750 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003751 goto qsec_out;
3752 }
3753
3754/* BB check that data area is minimum length and as big as acl_len */
3755
Steve Frenchaf6f4612007-10-16 18:40:37 +00003756 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003757 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003758 cifs_dbg(VFS, "acl length %d does not match %d\n",
3759 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003760 if (*pbuflen > acl_len)
3761 *pbuflen = acl_len;
3762 }
Steve French0a4b92c2006-01-12 15:44:21 -08003763
Steve French630f3f0c2007-10-25 21:17:17 +00003764 /* check if buffer is big enough for the acl
3765 header followed by the smallest SID */
3766 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3767 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003768 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003769 rc = -EINVAL;
3770 *pbuflen = 0;
3771 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003772 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003773 if (*acl_inf == NULL) {
3774 *pbuflen = 0;
3775 rc = -ENOMEM;
3776 }
Steve French630f3f0c2007-10-25 21:17:17 +00003777 }
Steve French0a4b92c2006-01-12 15:44:21 -08003778 }
3779qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003780 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003781 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003782 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003783 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003784/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003785 return rc;
3786}
Steve French97837582007-12-31 07:47:21 +00003787
3788int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003789CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003790 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003791{
3792 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3793 int rc = 0;
3794 int bytes_returned = 0;
3795 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003796 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003797
3798setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003799 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003800 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003801 return rc;
Steve French97837582007-12-31 07:47:21 +00003802
3803 pSMB->MaxSetupCount = 0;
3804 pSMB->Reserved = 0;
3805
3806 param_count = 8;
3807 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3808 data_count = acllen;
3809 data_offset = param_offset + param_count;
3810 byte_count = 3 /* pad */ + param_count;
3811
3812 pSMB->DataCount = cpu_to_le32(data_count);
3813 pSMB->TotalDataCount = pSMB->DataCount;
3814 pSMB->MaxParameterCount = cpu_to_le32(4);
3815 pSMB->MaxDataCount = cpu_to_le32(16384);
3816 pSMB->ParameterCount = cpu_to_le32(param_count);
3817 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3818 pSMB->TotalParameterCount = pSMB->ParameterCount;
3819 pSMB->DataOffset = cpu_to_le32(data_offset);
3820 pSMB->SetupCount = 0;
3821 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3822 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3823
3824 pSMB->Fid = fid; /* file handle always le */
3825 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003826 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003827
3828 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003829 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3830 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003831 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003832 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003833 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003834
3835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3837
Joe Perchesf96637b2013-05-04 22:12:25 -05003838 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3839 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003840 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003841 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003842 cifs_buf_release(pSMB);
3843
3844 if (rc == -EAGAIN)
3845 goto setCifsAclRetry;
3846
3847 return (rc);
3848}
3849
Jeff Layton79df1ba2010-12-06 12:52:08 -05003850#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003851
Steve French6b8edfe2005-08-23 20:26:03 -07003852/* Legacy Query Path Information call for lookup to old servers such
3853 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003854int
3855SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3856 const char *search_name, FILE_ALL_INFO *data,
3857 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003858{
Steve Frenchad7a2922008-02-07 23:25:02 +00003859 QUERY_INFORMATION_REQ *pSMB;
3860 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003861 int rc = 0;
3862 int bytes_returned;
3863 int name_len;
3864
Joe Perchesf96637b2013-05-04 22:12:25 -05003865 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003866QInfRetry:
3867 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003868 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003869 if (rc)
3870 return rc;
3871
3872 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3873 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003874 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003875 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003876 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003877 name_len++; /* trailing null */
3878 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003879 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003880 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003881 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003882 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003883 }
3884 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003885 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003886 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003887 pSMB->ByteCount = cpu_to_le16(name_len);
3888
3889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003891 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003892 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003893 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003894 struct timespec ts;
3895 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003896
3897 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003898 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003899 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003900 ts.tv_nsec = 0;
3901 ts.tv_sec = time;
3902 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003903 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3904 data->LastWriteTime = data->ChangeTime;
3905 data->LastAccessTime = 0;
3906 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003907 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003908 data->EndOfFile = data->AllocationSize;
3909 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003910 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003911 } else
3912 rc = -EIO; /* bad buffer passed in */
3913
3914 cifs_buf_release(pSMB);
3915
3916 if (rc == -EAGAIN)
3917 goto QInfRetry;
3918
3919 return rc;
3920}
3921
Jeff Laytonbcd53572010-02-12 07:44:16 -05003922int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003923CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003924 u16 netfid, FILE_ALL_INFO *pFindData)
3925{
3926 struct smb_t2_qfi_req *pSMB = NULL;
3927 struct smb_t2_qfi_rsp *pSMBr = NULL;
3928 int rc = 0;
3929 int bytes_returned;
3930 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003931
Jeff Laytonbcd53572010-02-12 07:44:16 -05003932QFileInfoRetry:
3933 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3934 (void **) &pSMBr);
3935 if (rc)
3936 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003937
Jeff Laytonbcd53572010-02-12 07:44:16 -05003938 params = 2 /* level */ + 2 /* fid */;
3939 pSMB->t2.TotalDataCount = 0;
3940 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3941 /* BB find exact max data count below from sess structure BB */
3942 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3943 pSMB->t2.MaxSetupCount = 0;
3944 pSMB->t2.Reserved = 0;
3945 pSMB->t2.Flags = 0;
3946 pSMB->t2.Timeout = 0;
3947 pSMB->t2.Reserved2 = 0;
3948 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3949 Fid) - 4);
3950 pSMB->t2.DataCount = 0;
3951 pSMB->t2.DataOffset = 0;
3952 pSMB->t2.SetupCount = 1;
3953 pSMB->t2.Reserved3 = 0;
3954 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3955 byte_count = params + 1 /* pad */ ;
3956 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3957 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3958 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3959 pSMB->Pad = 0;
3960 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003961 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003962
3963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3965 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003966 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003967 } else { /* decode response */
3968 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3969
3970 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3971 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003972 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003973 rc = -EIO; /* bad smb */
3974 else if (pFindData) {
3975 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3976 memcpy((char *) pFindData,
3977 (char *) &pSMBr->hdr.Protocol +
3978 data_offset, sizeof(FILE_ALL_INFO));
3979 } else
3980 rc = -ENOMEM;
3981 }
3982 cifs_buf_release(pSMB);
3983 if (rc == -EAGAIN)
3984 goto QFileInfoRetry;
3985
3986 return rc;
3987}
Steve French6b8edfe2005-08-23 20:26:03 -07003988
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003990CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003991 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003992 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003993 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003995 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 TRANSACTION2_QPI_REQ *pSMB = NULL;
3997 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3998 int rc = 0;
3999 int bytes_returned;
4000 int name_len;
4001 __u16 params, byte_count;
4002
Joe Perchesf96637b2013-05-04 22:12:25 -05004003 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004QPathInfoRetry:
4005 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4006 (void **) &pSMBr);
4007 if (rc)
4008 return rc;
4009
4010 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4011 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004012 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004013 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 name_len++; /* trailing null */
4015 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004016 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004017 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004019 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 }
4021
Steve French50c2f752007-07-13 00:33:32 +00004022 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 pSMB->TotalDataCount = 0;
4024 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004025 /* BB find exact max SMB PDU from sess structure BB */
4026 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 pSMB->MaxSetupCount = 0;
4028 pSMB->Reserved = 0;
4029 pSMB->Flags = 0;
4030 pSMB->Timeout = 0;
4031 pSMB->Reserved2 = 0;
4032 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004033 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 pSMB->DataCount = 0;
4035 pSMB->DataOffset = 0;
4036 pSMB->SetupCount = 1;
4037 pSMB->Reserved3 = 0;
4038 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4039 byte_count = params + 1 /* pad */ ;
4040 pSMB->TotalParameterCount = cpu_to_le16(params);
4041 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004042 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004043 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4044 else
4045 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004047 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 pSMB->ByteCount = cpu_to_le16(byte_count);
4049
4050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4052 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004053 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 } else { /* decode response */
4055 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4056
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004057 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4058 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004059 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004061 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004062 rc = -EIO; /* 24 or 26 expected but we do not read
4063 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004064 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004065 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004067
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004068 /*
4069 * On legacy responses we do not read the last field,
4070 * EAsize, fortunately since it varies by subdialect and
4071 * also note it differs on Set vs Get, ie two bytes or 4
4072 * bytes depending but we don't care here.
4073 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004074 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004075 size = sizeof(FILE_INFO_STANDARD);
4076 else
4077 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004078 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004079 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 } else
4081 rc = -ENOMEM;
4082 }
4083 cifs_buf_release(pSMB);
4084 if (rc == -EAGAIN)
4085 goto QPathInfoRetry;
4086
4087 return rc;
4088}
4089
4090int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004091CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004092 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4093{
4094 struct smb_t2_qfi_req *pSMB = NULL;
4095 struct smb_t2_qfi_rsp *pSMBr = NULL;
4096 int rc = 0;
4097 int bytes_returned;
4098 __u16 params, byte_count;
4099
4100UnixQFileInfoRetry:
4101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4102 (void **) &pSMBr);
4103 if (rc)
4104 return rc;
4105
4106 params = 2 /* level */ + 2 /* fid */;
4107 pSMB->t2.TotalDataCount = 0;
4108 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4109 /* BB find exact max data count below from sess structure BB */
4110 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4111 pSMB->t2.MaxSetupCount = 0;
4112 pSMB->t2.Reserved = 0;
4113 pSMB->t2.Flags = 0;
4114 pSMB->t2.Timeout = 0;
4115 pSMB->t2.Reserved2 = 0;
4116 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4117 Fid) - 4);
4118 pSMB->t2.DataCount = 0;
4119 pSMB->t2.DataOffset = 0;
4120 pSMB->t2.SetupCount = 1;
4121 pSMB->t2.Reserved3 = 0;
4122 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4123 byte_count = params + 1 /* pad */ ;
4124 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4125 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4126 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4127 pSMB->Pad = 0;
4128 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004129 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004130
4131 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4132 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4133 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004134 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004135 } else { /* decode response */
4136 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4137
Jeff Layton820a8032011-05-04 08:05:26 -04004138 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004139 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 -05004140 rc = -EIO; /* bad smb */
4141 } else {
4142 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4143 memcpy((char *) pFindData,
4144 (char *) &pSMBr->hdr.Protocol +
4145 data_offset,
4146 sizeof(FILE_UNIX_BASIC_INFO));
4147 }
4148 }
4149
4150 cifs_buf_release(pSMB);
4151 if (rc == -EAGAIN)
4152 goto UnixQFileInfoRetry;
4153
4154 return rc;
4155}
4156
4157int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004158CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004160 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004161 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162{
4163/* SMB_QUERY_FILE_UNIX_BASIC */
4164 TRANSACTION2_QPI_REQ *pSMB = NULL;
4165 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4166 int rc = 0;
4167 int bytes_returned = 0;
4168 int name_len;
4169 __u16 params, byte_count;
4170
Joe Perchesf96637b2013-05-04 22:12:25 -05004171 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172UnixQPathInfoRetry:
4173 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4174 (void **) &pSMBr);
4175 if (rc)
4176 return rc;
4177
4178 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4179 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004180 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4181 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 name_len++; /* trailing null */
4183 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004184 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 name_len = strnlen(searchName, PATH_MAX);
4186 name_len++; /* trailing null */
4187 strncpy(pSMB->FileName, searchName, name_len);
4188 }
4189
Steve French50c2f752007-07-13 00:33:32 +00004190 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 pSMB->TotalDataCount = 0;
4192 pSMB->MaxParameterCount = cpu_to_le16(2);
4193 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004194 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 pSMB->MaxSetupCount = 0;
4196 pSMB->Reserved = 0;
4197 pSMB->Flags = 0;
4198 pSMB->Timeout = 0;
4199 pSMB->Reserved2 = 0;
4200 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004201 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 pSMB->DataCount = 0;
4203 pSMB->DataOffset = 0;
4204 pSMB->SetupCount = 1;
4205 pSMB->Reserved3 = 0;
4206 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4207 byte_count = params + 1 /* pad */ ;
4208 pSMB->TotalParameterCount = cpu_to_le16(params);
4209 pSMB->ParameterCount = pSMB->TotalParameterCount;
4210 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4211 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004212 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 pSMB->ByteCount = cpu_to_le16(byte_count);
4214
4215 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4216 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4217 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004218 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 } else { /* decode response */
4220 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4221
Jeff Layton820a8032011-05-04 08:05:26 -04004222 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004223 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 -07004224 rc = -EIO; /* bad smb */
4225 } else {
4226 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4227 memcpy((char *) pFindData,
4228 (char *) &pSMBr->hdr.Protocol +
4229 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004230 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 }
4232 }
4233 cifs_buf_release(pSMB);
4234 if (rc == -EAGAIN)
4235 goto UnixQPathInfoRetry;
4236
4237 return rc;
4238}
4239
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240/* xid, tcon, searchName and codepage are input parms, rest are returned */
4241int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004242CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004243 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004244 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004245 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246{
4247/* level 257 SMB_ */
4248 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4249 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004250 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 int rc = 0;
4252 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004253 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004255 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256
Joe Perchesf96637b2013-05-04 22:12:25 -05004257 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
4259findFirstRetry:
4260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4261 (void **) &pSMBr);
4262 if (rc)
4263 return rc;
4264
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004265 nls_codepage = cifs_sb->local_nls;
4266 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4267
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4269 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004270 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4271 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004272 /* We can not add the asterik earlier in case
4273 it got remapped to 0xF03A as if it were part of the
4274 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004276 if (msearch) {
4277 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4278 pSMB->FileName[name_len+1] = 0;
4279 pSMB->FileName[name_len+2] = '*';
4280 pSMB->FileName[name_len+3] = 0;
4281 name_len += 4; /* now the trailing null */
4282 /* null terminate just in case */
4283 pSMB->FileName[name_len] = 0;
4284 pSMB->FileName[name_len+1] = 0;
4285 name_len += 2;
4286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 } else { /* BB add check for overrun of SMB buf BB */
4288 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004290 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 free buffer exit; BB */
4292 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004293 if (msearch) {
4294 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4295 pSMB->FileName[name_len+1] = '*';
4296 pSMB->FileName[name_len+2] = 0;
4297 name_len += 3;
4298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 }
4300
4301 params = 12 + name_len /* includes null */ ;
4302 pSMB->TotalDataCount = 0; /* no EAs */
4303 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004304 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 pSMB->MaxSetupCount = 0;
4306 pSMB->Reserved = 0;
4307 pSMB->Flags = 0;
4308 pSMB->Timeout = 0;
4309 pSMB->Reserved2 = 0;
4310 byte_count = params + 1 /* pad */ ;
4311 pSMB->TotalParameterCount = cpu_to_le16(params);
4312 pSMB->ParameterCount = pSMB->TotalParameterCount;
4313 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004314 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4315 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 pSMB->DataCount = 0;
4317 pSMB->DataOffset = 0;
4318 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4319 pSMB->Reserved3 = 0;
4320 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4321 pSMB->SearchAttributes =
4322 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4323 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004324 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004325 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4327
4328 /* BB what should we set StorageType to? Does it matter? BB */
4329 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004330 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 pSMB->ByteCount = cpu_to_le16(byte_count);
4332
4333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004335 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
Steve French88274812006-03-09 22:21:45 +00004337 if (rc) {/* BB add logic to retry regular search if Unix search
4338 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004340 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004341
Steve French88274812006-03-09 22:21:45 +00004342 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
4344 /* BB eventually could optimize out free and realloc of buf */
4345 /* for this case */
4346 if (rc == -EAGAIN)
4347 goto findFirstRetry;
4348 } else { /* decode response */
4349 /* BB remember to free buffer if error BB */
4350 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004351 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004352 unsigned int lnoff;
4353
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004355 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 else
Steve French4b18f2a2008-04-29 00:06:05 +00004357 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358
4359 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004360 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004361 psrch_inf->srch_entries_start =
4362 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4365 le16_to_cpu(pSMBr->t2.ParameterOffset));
4366
Steve French790fe572007-07-07 19:25:05 +00004367 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004368 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 else
Steve French4b18f2a2008-04-29 00:06:05 +00004370 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371
Steve French50c2f752007-07-13 00:33:32 +00004372 psrch_inf->entries_in_buffer =
4373 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004374 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004376 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004377 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004378 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004379 psrch_inf->last_entry = NULL;
4380 return rc;
4381 }
4382
Steve French0752f152008-10-07 20:03:33 +00004383 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004384 lnoff;
4385
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004386 if (pnetfid)
4387 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 } else {
4389 cifs_buf_release(pSMB);
4390 }
4391 }
4392
4393 return rc;
4394}
4395
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004396int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4397 __u16 searchHandle, __u16 search_flags,
4398 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399{
4400 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4401 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004402 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 char *response_data;
4404 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004405 int bytes_returned;
4406 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 __u16 params, byte_count;
4408
Joe Perchesf96637b2013-05-04 22:12:25 -05004409 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410
Steve French4b18f2a2008-04-29 00:06:05 +00004411 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 return -ENOENT;
4413
4414 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4415 (void **) &pSMBr);
4416 if (rc)
4417 return rc;
4418
Steve French50c2f752007-07-13 00:33:32 +00004419 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 byte_count = 0;
4421 pSMB->TotalDataCount = 0; /* no EAs */
4422 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004423 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 pSMB->MaxSetupCount = 0;
4425 pSMB->Reserved = 0;
4426 pSMB->Flags = 0;
4427 pSMB->Timeout = 0;
4428 pSMB->Reserved2 = 0;
4429 pSMB->ParameterOffset = cpu_to_le16(
4430 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4431 pSMB->DataCount = 0;
4432 pSMB->DataOffset = 0;
4433 pSMB->SetupCount = 1;
4434 pSMB->Reserved3 = 0;
4435 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4436 pSMB->SearchHandle = searchHandle; /* always kept as le */
4437 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004438 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4440 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004441 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442
4443 name_len = psrch_inf->resume_name_len;
4444 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004445 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4447 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004448 /* 14 byte parm len above enough for 2 byte null terminator */
4449 pSMB->ResumeFileName[name_len] = 0;
4450 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 } else {
4452 rc = -EINVAL;
4453 goto FNext2_err_exit;
4454 }
4455 byte_count = params + 1 /* pad */ ;
4456 pSMB->TotalParameterCount = cpu_to_le16(params);
4457 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004458 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4462 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004463 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 if (rc) {
4465 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004466 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004467 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004468 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004470 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 } else { /* decode response */
4472 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004473
Steve French790fe572007-07-07 19:25:05 +00004474 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004475 unsigned int lnoff;
4476
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 /* BB fixme add lock for file (srch_info) struct here */
4478 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004479 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 else
Steve French4b18f2a2008-04-29 00:06:05 +00004481 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 response_data = (char *) &pSMBr->hdr.Protocol +
4483 le16_to_cpu(pSMBr->t2.ParameterOffset);
4484 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4485 response_data = (char *)&pSMBr->hdr.Protocol +
4486 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004487 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004488 cifs_small_buf_release(
4489 psrch_inf->ntwrk_buf_start);
4490 else
4491 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 psrch_inf->srch_entries_start = response_data;
4493 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004494 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004495 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004496 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 else
Steve French4b18f2a2008-04-29 00:06:05 +00004498 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004499 psrch_inf->entries_in_buffer =
4500 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 psrch_inf->index_of_last_entry +=
4502 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004503 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004504 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004505 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004506 psrch_inf->last_entry = NULL;
4507 return rc;
4508 } else
4509 psrch_inf->last_entry =
4510 psrch_inf->srch_entries_start + lnoff;
4511
Joe Perchesf96637b2013-05-04 22:12:25 -05004512/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4513 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514
4515 /* BB fixme add unlock here */
4516 }
4517
4518 }
4519
4520 /* BB On error, should we leave previous search buf (and count and
4521 last entry fields) intact or free the previous one? */
4522
4523 /* Note: On -EAGAIN error only caller can retry on handle based calls
4524 since file handle passed in no longer valid */
4525FNext2_err_exit:
4526 if (rc != 0)
4527 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 return rc;
4529}
4530
4531int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004532CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004533 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534{
4535 int rc = 0;
4536 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
Joe Perchesf96637b2013-05-04 22:12:25 -05004538 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4540
4541 /* no sense returning error if session restarted
4542 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004543 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 return 0;
4545 if (rc)
4546 return rc;
4547
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 pSMB->FileID = searchHandle;
4549 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004550 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004551 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004552 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004553
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004554 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
4556 /* Since session is dead, search handle closed on server already */
4557 if (rc == -EAGAIN)
4558 rc = 0;
4559
4560 return rc;
4561}
4562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004564CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004565 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004566 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567{
4568 int rc = 0;
4569 TRANSACTION2_QPI_REQ *pSMB = NULL;
4570 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4571 int name_len, bytes_returned;
4572 __u16 params, byte_count;
4573
Joe Perchesf96637b2013-05-04 22:12:25 -05004574 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004575 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004576 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
4578GetInodeNumberRetry:
4579 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004580 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 if (rc)
4582 return rc;
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4585 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004586 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004587 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004588 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 name_len++; /* trailing null */
4590 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004591 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004592 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004594 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 }
4596
4597 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4598 pSMB->TotalDataCount = 0;
4599 pSMB->MaxParameterCount = cpu_to_le16(2);
4600 /* BB find exact max data count below from sess structure BB */
4601 pSMB->MaxDataCount = cpu_to_le16(4000);
4602 pSMB->MaxSetupCount = 0;
4603 pSMB->Reserved = 0;
4604 pSMB->Flags = 0;
4605 pSMB->Timeout = 0;
4606 pSMB->Reserved2 = 0;
4607 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004608 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 pSMB->DataCount = 0;
4610 pSMB->DataOffset = 0;
4611 pSMB->SetupCount = 1;
4612 pSMB->Reserved3 = 0;
4613 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4614 byte_count = params + 1 /* pad */ ;
4615 pSMB->TotalParameterCount = cpu_to_le16(params);
4616 pSMB->ParameterCount = pSMB->TotalParameterCount;
4617 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4618 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004619 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->ByteCount = cpu_to_le16(byte_count);
4621
4622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4623 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4624 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004625 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 } else {
4627 /* decode response */
4628 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004630 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 /* If rc should we check for EOPNOSUPP and
4632 disable the srvino flag? or in caller? */
4633 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004634 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4636 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004637 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004639 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004640 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 rc = -EIO;
4642 goto GetInodeNumOut;
4643 }
4644 pfinfo = (struct file_internal_info *)
4645 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004646 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 }
4648 }
4649GetInodeNumOut:
4650 cifs_buf_release(pSMB);
4651 if (rc == -EAGAIN)
4652 goto GetInodeNumberRetry;
4653 return rc;
4654}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655
Igor Mammedovfec45852008-05-16 13:06:30 +04004656/* parses DFS refferal V3 structure
4657 * caller is responsible for freeing target_nodes
4658 * returns:
4659 * on success - 0
4660 * on failure - errno
4661 */
4662static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004663parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004664 unsigned int *num_of_nodes,
4665 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004666 const struct nls_table *nls_codepage, int remap,
4667 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004668{
4669 int i, rc = 0;
4670 char *data_end;
4671 bool is_unicode;
4672 struct dfs_referral_level_3 *ref;
4673
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004674 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4675 is_unicode = true;
4676 else
4677 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004678 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4679
4680 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004681 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4682 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004683 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004684 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 }
4686
4687 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004688 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004689 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4690 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004691 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004692 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004693 }
4694
4695 /* get the upper boundary of the resp buffer */
4696 data_end = (char *)(&(pSMBr->PathConsumed)) +
4697 le16_to_cpu(pSMBr->t2.DataCount);
4698
Joe Perchesf96637b2013-05-04 22:12:25 -05004699 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4700 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004701
Joe Perchesf96637b2013-05-04 22:12:25 -05004702 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4703 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004704 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004705 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004706 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004707 }
4708
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004709 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004710 for (i = 0; i < *num_of_nodes; i++) {
4711 char *temp;
4712 int max_len;
4713 struct dfs_info3_param *node = (*target_nodes)+i;
4714
Steve French0e0d2cf2009-05-01 05:27:32 +00004715 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004716 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004717 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4718 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004719 if (tmp == NULL) {
4720 rc = -ENOMEM;
4721 goto parse_DFS_referrals_exit;
4722 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004723 cifsConvertToUTF16((__le16 *) tmp, searchName,
4724 PATH_MAX, nls_codepage, remap);
4725 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004726 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004727 nls_codepage);
4728 kfree(tmp);
4729 } else
4730 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4731
Igor Mammedovfec45852008-05-16 13:06:30 +04004732 node->server_type = le16_to_cpu(ref->ServerType);
4733 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4734
4735 /* copy DfsPath */
4736 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4737 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004738 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4739 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004740 if (!node->path_name) {
4741 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004742 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004743 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004744
4745 /* copy link target UNC */
4746 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4747 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004748 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4749 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004750 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004751 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004752 goto parse_DFS_referrals_exit;
4753 }
4754
4755 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004756 }
4757
Steve Frencha1fe78f2008-05-16 18:48:38 +00004758parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004759 if (rc) {
4760 free_dfs_info_array(*target_nodes, *num_of_nodes);
4761 *target_nodes = NULL;
4762 *num_of_nodes = 0;
4763 }
4764 return rc;
4765}
4766
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004768CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004769 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004770 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004771 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772{
4773/* TRANS2_GET_DFS_REFERRAL */
4774 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4775 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 int rc = 0;
4777 int bytes_returned;
4778 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004780 *num_of_nodes = 0;
4781 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782
Joe Perchesf96637b2013-05-04 22:12:25 -05004783 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 if (ses == NULL)
4785 return -ENODEV;
4786getDFSRetry:
4787 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4788 (void **) &pSMBr);
4789 if (rc)
4790 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004791
4792 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004793 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004794 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 pSMB->hdr.Tid = ses->ipc_tid;
4796 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004797 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004799 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801
4802 if (ses->capabilities & CAP_UNICODE) {
4803 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4804 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004805 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004806 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004807 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 name_len++; /* trailing null */
4809 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004810 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004811 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004813 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 }
4815
Steve French790fe572007-07-07 19:25:05 +00004816 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004817 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004818 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4819 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4820 }
4821
Steve French50c2f752007-07-13 00:33:32 +00004822 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004823
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 params = 2 /* level */ + name_len /*includes null */ ;
4825 pSMB->TotalDataCount = 0;
4826 pSMB->DataCount = 0;
4827 pSMB->DataOffset = 0;
4828 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004829 /* BB find exact max SMB PDU from sess structure BB */
4830 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 pSMB->MaxSetupCount = 0;
4832 pSMB->Reserved = 0;
4833 pSMB->Flags = 0;
4834 pSMB->Timeout = 0;
4835 pSMB->Reserved2 = 0;
4836 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004837 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 pSMB->SetupCount = 1;
4839 pSMB->Reserved3 = 0;
4840 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4841 byte_count = params + 3 /* pad */ ;
4842 pSMB->ParameterCount = cpu_to_le16(params);
4843 pSMB->TotalParameterCount = pSMB->ParameterCount;
4844 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004845 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 pSMB->ByteCount = cpu_to_le16(byte_count);
4847
4848 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4849 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4850 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004851 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004852 goto GetDFSRefExit;
4853 }
4854 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004856 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004857 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004858 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004859 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004861
Joe Perchesf96637b2013-05-04 22:12:25 -05004862 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4863 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004864
4865 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004866 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004867 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004868 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004869
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004871 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872
4873 if (rc == -EAGAIN)
4874 goto getDFSRetry;
4875
4876 return rc;
4877}
4878
Steve French20962432005-09-21 22:05:57 -07004879/* Query File System Info such as free space to old servers such as Win 9x */
4880int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004881SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4882 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004883{
4884/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4885 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4886 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4887 FILE_SYSTEM_ALLOC_INFO *response_data;
4888 int rc = 0;
4889 int bytes_returned = 0;
4890 __u16 params, byte_count;
4891
Joe Perchesf96637b2013-05-04 22:12:25 -05004892 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004893oldQFSInfoRetry:
4894 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4895 (void **) &pSMBr);
4896 if (rc)
4897 return rc;
Steve French20962432005-09-21 22:05:57 -07004898
4899 params = 2; /* level */
4900 pSMB->TotalDataCount = 0;
4901 pSMB->MaxParameterCount = cpu_to_le16(2);
4902 pSMB->MaxDataCount = cpu_to_le16(1000);
4903 pSMB->MaxSetupCount = 0;
4904 pSMB->Reserved = 0;
4905 pSMB->Flags = 0;
4906 pSMB->Timeout = 0;
4907 pSMB->Reserved2 = 0;
4908 byte_count = params + 1 /* pad */ ;
4909 pSMB->TotalParameterCount = cpu_to_le16(params);
4910 pSMB->ParameterCount = pSMB->TotalParameterCount;
4911 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4912 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4913 pSMB->DataCount = 0;
4914 pSMB->DataOffset = 0;
4915 pSMB->SetupCount = 1;
4916 pSMB->Reserved3 = 0;
4917 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4918 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004919 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004920 pSMB->ByteCount = cpu_to_le16(byte_count);
4921
4922 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4923 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4924 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004925 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004926 } else { /* decode response */
4927 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4928
Jeff Layton820a8032011-05-04 08:05:26 -04004929 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004930 rc = -EIO; /* bad smb */
4931 else {
4932 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004933 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004934 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004935
Steve French50c2f752007-07-13 00:33:32 +00004936 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004937 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4938 FSData->f_bsize =
4939 le16_to_cpu(response_data->BytesPerSector) *
4940 le32_to_cpu(response_data->
4941 SectorsPerAllocationUnit);
4942 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004943 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004944 FSData->f_bfree = FSData->f_bavail =
4945 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004946 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4947 (unsigned long long)FSData->f_blocks,
4948 (unsigned long long)FSData->f_bfree,
4949 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004950 }
4951 }
4952 cifs_buf_release(pSMB);
4953
4954 if (rc == -EAGAIN)
4955 goto oldQFSInfoRetry;
4956
4957 return rc;
4958}
4959
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004961CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4962 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963{
4964/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4965 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4966 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4967 FILE_SYSTEM_INFO *response_data;
4968 int rc = 0;
4969 int bytes_returned = 0;
4970 __u16 params, byte_count;
4971
Joe Perchesf96637b2013-05-04 22:12:25 -05004972 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973QFSInfoRetry:
4974 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4975 (void **) &pSMBr);
4976 if (rc)
4977 return rc;
4978
4979 params = 2; /* level */
4980 pSMB->TotalDataCount = 0;
4981 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004982 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 pSMB->MaxSetupCount = 0;
4984 pSMB->Reserved = 0;
4985 pSMB->Flags = 0;
4986 pSMB->Timeout = 0;
4987 pSMB->Reserved2 = 0;
4988 byte_count = params + 1 /* pad */ ;
4989 pSMB->TotalParameterCount = cpu_to_le16(params);
4990 pSMB->ParameterCount = pSMB->TotalParameterCount;
4991 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004992 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 pSMB->DataCount = 0;
4994 pSMB->DataOffset = 0;
4995 pSMB->SetupCount = 1;
4996 pSMB->Reserved3 = 0;
4997 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4998 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004999 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 pSMB->ByteCount = cpu_to_le16(byte_count);
5001
5002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5004 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005005 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005007 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
Jeff Layton820a8032011-05-04 08:05:26 -04005009 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 rc = -EIO; /* bad smb */
5011 else {
5012 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013
5014 response_data =
5015 (FILE_SYSTEM_INFO
5016 *) (((char *) &pSMBr->hdr.Protocol) +
5017 data_offset);
5018 FSData->f_bsize =
5019 le32_to_cpu(response_data->BytesPerSector) *
5020 le32_to_cpu(response_data->
5021 SectorsPerAllocationUnit);
5022 FSData->f_blocks =
5023 le64_to_cpu(response_data->TotalAllocationUnits);
5024 FSData->f_bfree = FSData->f_bavail =
5025 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005026 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5027 (unsigned long long)FSData->f_blocks,
5028 (unsigned long long)FSData->f_bfree,
5029 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 }
5031 }
5032 cifs_buf_release(pSMB);
5033
5034 if (rc == -EAGAIN)
5035 goto QFSInfoRetry;
5036
5037 return rc;
5038}
5039
5040int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005041CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042{
5043/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5044 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5045 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5046 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5047 int rc = 0;
5048 int bytes_returned = 0;
5049 __u16 params, byte_count;
5050
Joe Perchesf96637b2013-05-04 22:12:25 -05005051 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052QFSAttributeRetry:
5053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5054 (void **) &pSMBr);
5055 if (rc)
5056 return rc;
5057
5058 params = 2; /* level */
5059 pSMB->TotalDataCount = 0;
5060 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005061 /* BB find exact max SMB PDU from sess structure BB */
5062 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 pSMB->MaxSetupCount = 0;
5064 pSMB->Reserved = 0;
5065 pSMB->Flags = 0;
5066 pSMB->Timeout = 0;
5067 pSMB->Reserved2 = 0;
5068 byte_count = params + 1 /* pad */ ;
5069 pSMB->TotalParameterCount = cpu_to_le16(params);
5070 pSMB->ParameterCount = pSMB->TotalParameterCount;
5071 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005072 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 pSMB->DataCount = 0;
5074 pSMB->DataOffset = 0;
5075 pSMB->SetupCount = 1;
5076 pSMB->Reserved3 = 0;
5077 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5078 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005079 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 pSMB->ByteCount = cpu_to_le16(byte_count);
5081
5082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5084 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005085 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 } else { /* decode response */
5087 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5088
Jeff Layton820a8032011-05-04 08:05:26 -04005089 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005090 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 rc = -EIO; /* bad smb */
5092 } else {
5093 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5094 response_data =
5095 (FILE_SYSTEM_ATTRIBUTE_INFO
5096 *) (((char *) &pSMBr->hdr.Protocol) +
5097 data_offset);
5098 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005099 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 }
5101 }
5102 cifs_buf_release(pSMB);
5103
5104 if (rc == -EAGAIN)
5105 goto QFSAttributeRetry;
5106
5107 return rc;
5108}
5109
5110int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005111CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112{
5113/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5114 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5115 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5116 FILE_SYSTEM_DEVICE_INFO *response_data;
5117 int rc = 0;
5118 int bytes_returned = 0;
5119 __u16 params, byte_count;
5120
Joe Perchesf96637b2013-05-04 22:12:25 -05005121 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122QFSDeviceRetry:
5123 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5124 (void **) &pSMBr);
5125 if (rc)
5126 return rc;
5127
5128 params = 2; /* level */
5129 pSMB->TotalDataCount = 0;
5130 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005131 /* BB find exact max SMB PDU from sess structure BB */
5132 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 pSMB->MaxSetupCount = 0;
5134 pSMB->Reserved = 0;
5135 pSMB->Flags = 0;
5136 pSMB->Timeout = 0;
5137 pSMB->Reserved2 = 0;
5138 byte_count = params + 1 /* pad */ ;
5139 pSMB->TotalParameterCount = cpu_to_le16(params);
5140 pSMB->ParameterCount = pSMB->TotalParameterCount;
5141 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005142 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
5144 pSMB->DataCount = 0;
5145 pSMB->DataOffset = 0;
5146 pSMB->SetupCount = 1;
5147 pSMB->Reserved3 = 0;
5148 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5149 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005150 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 pSMB->ByteCount = cpu_to_le16(byte_count);
5152
5153 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5154 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5155 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005156 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 } else { /* decode response */
5158 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5159
Jeff Layton820a8032011-05-04 08:05:26 -04005160 if (rc || get_bcc(&pSMBr->hdr) <
5161 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 rc = -EIO; /* bad smb */
5163 else {
5164 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5165 response_data =
Steve French737b7582005-04-28 22:41:06 -07005166 (FILE_SYSTEM_DEVICE_INFO *)
5167 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 data_offset);
5169 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005170 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 }
5172 }
5173 cifs_buf_release(pSMB);
5174
5175 if (rc == -EAGAIN)
5176 goto QFSDeviceRetry;
5177
5178 return rc;
5179}
5180
5181int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005182CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183{
5184/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5185 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5186 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5187 FILE_SYSTEM_UNIX_INFO *response_data;
5188 int rc = 0;
5189 int bytes_returned = 0;
5190 __u16 params, byte_count;
5191
Joe Perchesf96637b2013-05-04 22:12:25 -05005192 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005194 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5195 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 if (rc)
5197 return rc;
5198
5199 params = 2; /* level */
5200 pSMB->TotalDataCount = 0;
5201 pSMB->DataCount = 0;
5202 pSMB->DataOffset = 0;
5203 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005204 /* BB find exact max SMB PDU from sess structure BB */
5205 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 pSMB->MaxSetupCount = 0;
5207 pSMB->Reserved = 0;
5208 pSMB->Flags = 0;
5209 pSMB->Timeout = 0;
5210 pSMB->Reserved2 = 0;
5211 byte_count = params + 1 /* pad */ ;
5212 pSMB->ParameterCount = cpu_to_le16(params);
5213 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005214 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5215 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 pSMB->SetupCount = 1;
5217 pSMB->Reserved3 = 0;
5218 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5219 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005220 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 pSMB->ByteCount = cpu_to_le16(byte_count);
5222
5223 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5224 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5225 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005226 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 } else { /* decode response */
5228 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5229
Jeff Layton820a8032011-05-04 08:05:26 -04005230 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 rc = -EIO; /* bad smb */
5232 } else {
5233 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5234 response_data =
5235 (FILE_SYSTEM_UNIX_INFO
5236 *) (((char *) &pSMBr->hdr.Protocol) +
5237 data_offset);
5238 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005239 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 }
5241 }
5242 cifs_buf_release(pSMB);
5243
5244 if (rc == -EAGAIN)
5245 goto QFSUnixRetry;
5246
5247
5248 return rc;
5249}
5250
Jeremy Allisonac670552005-06-22 17:26:35 -07005251int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005252CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005253{
5254/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5255 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5256 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5257 int rc = 0;
5258 int bytes_returned = 0;
5259 __u16 params, param_offset, offset, byte_count;
5260
Joe Perchesf96637b2013-05-04 22:12:25 -05005261 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005262SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005263 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005264 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5265 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005266 if (rc)
5267 return rc;
5268
5269 params = 4; /* 2 bytes zero followed by info level. */
5270 pSMB->MaxSetupCount = 0;
5271 pSMB->Reserved = 0;
5272 pSMB->Flags = 0;
5273 pSMB->Timeout = 0;
5274 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005275 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5276 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005277 offset = param_offset + params;
5278
5279 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005280 /* BB find exact max SMB PDU from sess structure BB */
5281 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005282 pSMB->SetupCount = 1;
5283 pSMB->Reserved3 = 0;
5284 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5285 byte_count = 1 /* pad */ + params + 12;
5286
5287 pSMB->DataCount = cpu_to_le16(12);
5288 pSMB->ParameterCount = cpu_to_le16(params);
5289 pSMB->TotalDataCount = pSMB->DataCount;
5290 pSMB->TotalParameterCount = pSMB->ParameterCount;
5291 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5292 pSMB->DataOffset = cpu_to_le16(offset);
5293
5294 /* Params. */
5295 pSMB->FileNum = 0;
5296 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5297
5298 /* Data. */
5299 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5300 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5301 pSMB->ClientUnixCap = cpu_to_le64(cap);
5302
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005303 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005304 pSMB->ByteCount = cpu_to_le16(byte_count);
5305
5306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5307 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5308 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005309 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005310 } else { /* decode response */
5311 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005312 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005313 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005314 }
5315 cifs_buf_release(pSMB);
5316
5317 if (rc == -EAGAIN)
5318 goto SETFSUnixRetry;
5319
5320 return rc;
5321}
5322
5323
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324
5325int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005326CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005327 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328{
5329/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5330 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5331 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5332 FILE_SYSTEM_POSIX_INFO *response_data;
5333 int rc = 0;
5334 int bytes_returned = 0;
5335 __u16 params, byte_count;
5336
Joe Perchesf96637b2013-05-04 22:12:25 -05005337 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338QFSPosixRetry:
5339 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5340 (void **) &pSMBr);
5341 if (rc)
5342 return rc;
5343
5344 params = 2; /* level */
5345 pSMB->TotalDataCount = 0;
5346 pSMB->DataCount = 0;
5347 pSMB->DataOffset = 0;
5348 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005349 /* BB find exact max SMB PDU from sess structure BB */
5350 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 pSMB->MaxSetupCount = 0;
5352 pSMB->Reserved = 0;
5353 pSMB->Flags = 0;
5354 pSMB->Timeout = 0;
5355 pSMB->Reserved2 = 0;
5356 byte_count = params + 1 /* pad */ ;
5357 pSMB->ParameterCount = cpu_to_le16(params);
5358 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005359 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5360 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 pSMB->SetupCount = 1;
5362 pSMB->Reserved3 = 0;
5363 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5364 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005365 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 pSMB->ByteCount = cpu_to_le16(byte_count);
5367
5368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5369 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5370 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005371 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 } else { /* decode response */
5373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5374
Jeff Layton820a8032011-05-04 08:05:26 -04005375 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 rc = -EIO; /* bad smb */
5377 } else {
5378 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5379 response_data =
5380 (FILE_SYSTEM_POSIX_INFO
5381 *) (((char *) &pSMBr->hdr.Protocol) +
5382 data_offset);
5383 FSData->f_bsize =
5384 le32_to_cpu(response_data->BlockSize);
5385 FSData->f_blocks =
5386 le64_to_cpu(response_data->TotalBlocks);
5387 FSData->f_bfree =
5388 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005389 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 FSData->f_bavail = FSData->f_bfree;
5391 } else {
5392 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005393 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 }
Steve French790fe572007-07-07 19:25:05 +00005395 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005397 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005398 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005400 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 }
5402 }
5403 cifs_buf_release(pSMB);
5404
5405 if (rc == -EAGAIN)
5406 goto QFSPosixRetry;
5407
5408 return rc;
5409}
5410
5411
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005412/*
5413 * We can not use write of zero bytes trick to set file size due to need for
5414 * large file support. Also note that this SetPathInfo is preferred to
5415 * SetFileInfo based method in next routine which is only needed to work around
5416 * a sharing violation bugin Samba which this routine can run into.
5417 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005419CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005420 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5421 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422{
5423 struct smb_com_transaction2_spi_req *pSMB = NULL;
5424 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5425 struct file_end_of_file_info *parm_data;
5426 int name_len;
5427 int rc = 0;
5428 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005429 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5430
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 __u16 params, byte_count, data_count, param_offset, offset;
5432
Joe Perchesf96637b2013-05-04 22:12:25 -05005433 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434SetEOFRetry:
5435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5436 (void **) &pSMBr);
5437 if (rc)
5438 return rc;
5439
5440 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5441 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005442 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5443 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 name_len++; /* trailing null */
5445 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005446 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005447 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005449 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 }
5451 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005452 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005454 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 pSMB->MaxSetupCount = 0;
5456 pSMB->Reserved = 0;
5457 pSMB->Flags = 0;
5458 pSMB->Timeout = 0;
5459 pSMB->Reserved2 = 0;
5460 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005461 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005463 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005464 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5465 pSMB->InformationLevel =
5466 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5467 else
5468 pSMB->InformationLevel =
5469 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5470 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5472 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005473 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 else
5475 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005476 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 }
5478
5479 parm_data =
5480 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5481 offset);
5482 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5483 pSMB->DataOffset = cpu_to_le16(offset);
5484 pSMB->SetupCount = 1;
5485 pSMB->Reserved3 = 0;
5486 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5487 byte_count = 3 /* pad */ + params + data_count;
5488 pSMB->DataCount = cpu_to_le16(data_count);
5489 pSMB->TotalDataCount = pSMB->DataCount;
5490 pSMB->ParameterCount = cpu_to_le16(params);
5491 pSMB->TotalParameterCount = pSMB->ParameterCount;
5492 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005493 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 parm_data->FileSize = cpu_to_le64(size);
5495 pSMB->ByteCount = cpu_to_le16(byte_count);
5496 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5497 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005498 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005499 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500
5501 cifs_buf_release(pSMB);
5502
5503 if (rc == -EAGAIN)
5504 goto SetEOFRetry;
5505
5506 return rc;
5507}
5508
5509int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005510CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5511 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512{
5513 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 struct file_end_of_file_info *parm_data;
5515 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 __u16 params, param_offset, offset, byte_count, count;
5517
Joe Perchesf96637b2013-05-04 22:12:25 -05005518 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5519 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005520 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5521
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 if (rc)
5523 return rc;
5524
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005525 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5526 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005527
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 params = 6;
5529 pSMB->MaxSetupCount = 0;
5530 pSMB->Reserved = 0;
5531 pSMB->Flags = 0;
5532 pSMB->Timeout = 0;
5533 pSMB->Reserved2 = 0;
5534 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5535 offset = param_offset + params;
5536
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 count = sizeof(struct file_end_of_file_info);
5538 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005539 /* BB find exact max SMB PDU from sess structure BB */
5540 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 pSMB->SetupCount = 1;
5542 pSMB->Reserved3 = 0;
5543 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5544 byte_count = 3 /* pad */ + params + count;
5545 pSMB->DataCount = cpu_to_le16(count);
5546 pSMB->ParameterCount = cpu_to_le16(params);
5547 pSMB->TotalDataCount = pSMB->DataCount;
5548 pSMB->TotalParameterCount = pSMB->ParameterCount;
5549 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5550 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005551 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5552 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 pSMB->DataOffset = cpu_to_le16(offset);
5554 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005555 pSMB->Fid = cfile->fid.netfid;
5556 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5558 pSMB->InformationLevel =
5559 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5560 else
5561 pSMB->InformationLevel =
5562 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005563 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5565 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005566 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 else
5568 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005569 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 }
5571 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005572 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005574 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005576 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5577 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 }
5579
Steve French50c2f752007-07-13 00:33:32 +00005580 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 since file handle passed in no longer valid */
5582
5583 return rc;
5584}
5585
Steve French50c2f752007-07-13 00:33:32 +00005586/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 an open handle, rather than by pathname - this is awkward due to
5588 potential access conflicts on the open, but it is unavoidable for these
5589 old servers since the only other choice is to go from 100 nanosecond DCE
5590 time and resort to the original setpathinfo level which takes the ancient
5591 DOS time format with 2 second granularity */
5592int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005593CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005594 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595{
5596 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 char *data_offset;
5598 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 __u16 params, param_offset, offset, byte_count, count;
5600
Joe Perchesf96637b2013-05-04 22:12:25 -05005601 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005602 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5603
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 if (rc)
5605 return rc;
5606
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005607 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5608 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005609
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 params = 6;
5611 pSMB->MaxSetupCount = 0;
5612 pSMB->Reserved = 0;
5613 pSMB->Flags = 0;
5614 pSMB->Timeout = 0;
5615 pSMB->Reserved2 = 0;
5616 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5617 offset = param_offset + params;
5618
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005619 data_offset = (char *)pSMB +
5620 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621
Steve French26f57362007-08-30 22:09:15 +00005622 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005624 /* BB find max SMB PDU from sess */
5625 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 pSMB->SetupCount = 1;
5627 pSMB->Reserved3 = 0;
5628 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5629 byte_count = 3 /* pad */ + params + count;
5630 pSMB->DataCount = cpu_to_le16(count);
5631 pSMB->ParameterCount = cpu_to_le16(params);
5632 pSMB->TotalDataCount = pSMB->DataCount;
5633 pSMB->TotalParameterCount = pSMB->ParameterCount;
5634 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5635 pSMB->DataOffset = cpu_to_le16(offset);
5636 pSMB->Fid = fid;
5637 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5638 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5639 else
5640 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5641 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005642 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005644 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005645 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005646 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005647 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5648 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649
Steve French50c2f752007-07-13 00:33:32 +00005650 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 since file handle passed in no longer valid */
5652
5653 return rc;
5654}
5655
Jeff Layton6d22f092008-09-23 11:48:35 -04005656int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005657CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005658 bool delete_file, __u16 fid, __u32 pid_of_opener)
5659{
5660 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5661 char *data_offset;
5662 int rc = 0;
5663 __u16 params, param_offset, offset, byte_count, count;
5664
Joe Perchesf96637b2013-05-04 22:12:25 -05005665 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005666 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5667
5668 if (rc)
5669 return rc;
5670
5671 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5672 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5673
5674 params = 6;
5675 pSMB->MaxSetupCount = 0;
5676 pSMB->Reserved = 0;
5677 pSMB->Flags = 0;
5678 pSMB->Timeout = 0;
5679 pSMB->Reserved2 = 0;
5680 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5681 offset = param_offset + params;
5682
5683 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5684
5685 count = 1;
5686 pSMB->MaxParameterCount = cpu_to_le16(2);
5687 /* BB find max SMB PDU from sess */
5688 pSMB->MaxDataCount = cpu_to_le16(1000);
5689 pSMB->SetupCount = 1;
5690 pSMB->Reserved3 = 0;
5691 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5692 byte_count = 3 /* pad */ + params + count;
5693 pSMB->DataCount = cpu_to_le16(count);
5694 pSMB->ParameterCount = cpu_to_le16(params);
5695 pSMB->TotalDataCount = pSMB->DataCount;
5696 pSMB->TotalParameterCount = pSMB->ParameterCount;
5697 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5698 pSMB->DataOffset = cpu_to_le16(offset);
5699 pSMB->Fid = fid;
5700 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5701 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005702 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005703 pSMB->ByteCount = cpu_to_le16(byte_count);
5704 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005705 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005706 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005707 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005708
5709 return rc;
5710}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711
5712int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005713CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005714 const char *fileName, const FILE_BASIC_INFO *data,
5715 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716{
5717 TRANSACTION2_SPI_REQ *pSMB = NULL;
5718 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5719 int name_len;
5720 int rc = 0;
5721 int bytes_returned = 0;
5722 char *data_offset;
5723 __u16 params, param_offset, offset, byte_count, count;
5724
Joe Perchesf96637b2013-05-04 22:12:25 -05005725 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
5727SetTimesRetry:
5728 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5729 (void **) &pSMBr);
5730 if (rc)
5731 return rc;
5732
5733 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5734 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005735 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5736 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 name_len++; /* trailing null */
5738 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005739 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 name_len = strnlen(fileName, PATH_MAX);
5741 name_len++; /* trailing null */
5742 strncpy(pSMB->FileName, fileName, name_len);
5743 }
5744
5745 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005746 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005748 /* BB find max SMB PDU from sess structure BB */
5749 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 pSMB->MaxSetupCount = 0;
5751 pSMB->Reserved = 0;
5752 pSMB->Flags = 0;
5753 pSMB->Timeout = 0;
5754 pSMB->Reserved2 = 0;
5755 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005756 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 offset = param_offset + params;
5758 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5759 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5760 pSMB->DataOffset = cpu_to_le16(offset);
5761 pSMB->SetupCount = 1;
5762 pSMB->Reserved3 = 0;
5763 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5764 byte_count = 3 /* pad */ + params + count;
5765
5766 pSMB->DataCount = cpu_to_le16(count);
5767 pSMB->ParameterCount = cpu_to_le16(params);
5768 pSMB->TotalDataCount = pSMB->DataCount;
5769 pSMB->TotalParameterCount = pSMB->ParameterCount;
5770 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5771 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5772 else
5773 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5774 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005775 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005776 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 pSMB->ByteCount = cpu_to_le16(byte_count);
5778 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5779 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005780 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005781 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782
5783 cifs_buf_release(pSMB);
5784
5785 if (rc == -EAGAIN)
5786 goto SetTimesRetry;
5787
5788 return rc;
5789}
5790
5791/* Can not be used to set time stamps yet (due to old DOS time format) */
5792/* Can be used to set attributes */
5793#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5794 handling it anyway and NT4 was what we thought it would be needed for
5795 Do not delete it until we prove whether needed for Win9x though */
5796int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005797CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 __u16 dos_attrs, const struct nls_table *nls_codepage)
5799{
5800 SETATTR_REQ *pSMB = NULL;
5801 SETATTR_RSP *pSMBr = NULL;
5802 int rc = 0;
5803 int bytes_returned;
5804 int name_len;
5805
Joe Perchesf96637b2013-05-04 22:12:25 -05005806 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807
5808SetAttrLgcyRetry:
5809 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5810 (void **) &pSMBr);
5811 if (rc)
5812 return rc;
5813
5814 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5815 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005816 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5817 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 name_len++; /* trailing null */
5819 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005820 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 name_len = strnlen(fileName, PATH_MAX);
5822 name_len++; /* trailing null */
5823 strncpy(pSMB->fileName, fileName, name_len);
5824 }
5825 pSMB->attr = cpu_to_le16(dos_attrs);
5826 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005827 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005831 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005832 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833
5834 cifs_buf_release(pSMB);
5835
5836 if (rc == -EAGAIN)
5837 goto SetAttrLgcyRetry;
5838
5839 return rc;
5840}
5841#endif /* temporarily unneeded SetAttr legacy function */
5842
Jeff Layton654cf142009-07-09 20:02:49 -04005843static void
5844cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5845 const struct cifs_unix_set_info_args *args)
5846{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005847 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005848 u64 mode = args->mode;
5849
Eric W. Biederman49418b22013-02-06 00:57:56 -08005850 if (uid_valid(args->uid))
5851 uid = from_kuid(&init_user_ns, args->uid);
5852 if (gid_valid(args->gid))
5853 gid = from_kgid(&init_user_ns, args->gid);
5854
Jeff Layton654cf142009-07-09 20:02:49 -04005855 /*
5856 * Samba server ignores set of file size to zero due to bugs in some
5857 * older clients, but we should be precise - we use SetFileSize to
5858 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005859 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005860 * zero instead of -1 here
5861 */
5862 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5863 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5864 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5865 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5866 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005867 data_offset->Uid = cpu_to_le64(uid);
5868 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005869 /* better to leave device as zero when it is */
5870 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5871 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5872 data_offset->Permissions = cpu_to_le64(mode);
5873
5874 if (S_ISREG(mode))
5875 data_offset->Type = cpu_to_le32(UNIX_FILE);
5876 else if (S_ISDIR(mode))
5877 data_offset->Type = cpu_to_le32(UNIX_DIR);
5878 else if (S_ISLNK(mode))
5879 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5880 else if (S_ISCHR(mode))
5881 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5882 else if (S_ISBLK(mode))
5883 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5884 else if (S_ISFIFO(mode))
5885 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5886 else if (S_ISSOCK(mode))
5887 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5888}
5889
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005891CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005892 const struct cifs_unix_set_info_args *args,
5893 u16 fid, u32 pid_of_opener)
5894{
5895 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005896 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005897 int rc = 0;
5898 u16 params, param_offset, offset, byte_count, count;
5899
Joe Perchesf96637b2013-05-04 22:12:25 -05005900 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005901 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5902
5903 if (rc)
5904 return rc;
5905
5906 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5907 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5908
5909 params = 6;
5910 pSMB->MaxSetupCount = 0;
5911 pSMB->Reserved = 0;
5912 pSMB->Flags = 0;
5913 pSMB->Timeout = 0;
5914 pSMB->Reserved2 = 0;
5915 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5916 offset = param_offset + params;
5917
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005918 data_offset = (char *)pSMB +
5919 offsetof(struct smb_hdr, Protocol) + offset;
5920
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005921 count = sizeof(FILE_UNIX_BASIC_INFO);
5922
5923 pSMB->MaxParameterCount = cpu_to_le16(2);
5924 /* BB find max SMB PDU from sess */
5925 pSMB->MaxDataCount = cpu_to_le16(1000);
5926 pSMB->SetupCount = 1;
5927 pSMB->Reserved3 = 0;
5928 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5929 byte_count = 3 /* pad */ + params + count;
5930 pSMB->DataCount = cpu_to_le16(count);
5931 pSMB->ParameterCount = cpu_to_le16(params);
5932 pSMB->TotalDataCount = pSMB->DataCount;
5933 pSMB->TotalParameterCount = pSMB->ParameterCount;
5934 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5935 pSMB->DataOffset = cpu_to_le16(offset);
5936 pSMB->Fid = fid;
5937 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5938 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005939 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005940 pSMB->ByteCount = cpu_to_le16(byte_count);
5941
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005942 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005943
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005944 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005945 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005946 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5947 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005948
5949 /* Note: On -EAGAIN error only caller can retry on handle based calls
5950 since file handle passed in no longer valid */
5951
5952 return rc;
5953}
5954
5955int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005956CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005957 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005958 const struct cifs_unix_set_info_args *args,
5959 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960{
5961 TRANSACTION2_SPI_REQ *pSMB = NULL;
5962 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5963 int name_len;
5964 int rc = 0;
5965 int bytes_returned = 0;
5966 FILE_UNIX_BASIC_INFO *data_offset;
5967 __u16 params, param_offset, offset, count, byte_count;
5968
Joe Perchesf96637b2013-05-04 22:12:25 -05005969 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970setPermsRetry:
5971 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5972 (void **) &pSMBr);
5973 if (rc)
5974 return rc;
5975
5976 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5977 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005978 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005979 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 name_len++; /* trailing null */
5981 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005982 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005983 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005985 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986 }
5987
5988 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005989 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005991 /* BB find max SMB PDU from sess structure BB */
5992 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 pSMB->MaxSetupCount = 0;
5994 pSMB->Reserved = 0;
5995 pSMB->Flags = 0;
5996 pSMB->Timeout = 0;
5997 pSMB->Reserved2 = 0;
5998 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005999 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 offset = param_offset + params;
6001 data_offset =
6002 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6003 offset);
6004 memset(data_offset, 0, count);
6005 pSMB->DataOffset = cpu_to_le16(offset);
6006 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6007 pSMB->SetupCount = 1;
6008 pSMB->Reserved3 = 0;
6009 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6010 byte_count = 3 /* pad */ + params + count;
6011 pSMB->ParameterCount = cpu_to_le16(params);
6012 pSMB->DataCount = cpu_to_le16(count);
6013 pSMB->TotalParameterCount = pSMB->ParameterCount;
6014 pSMB->TotalDataCount = pSMB->DataCount;
6015 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6016 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006017 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006018
Jeff Layton654cf142009-07-09 20:02:49 -04006019 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020
6021 pSMB->ByteCount = cpu_to_le16(byte_count);
6022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006024 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006025 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026
Steve French0d817bc2008-05-22 02:02:03 +00006027 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 if (rc == -EAGAIN)
6029 goto setPermsRetry;
6030 return rc;
6031}
6032
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006034/*
6035 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6036 * function used by listxattr and getxattr type calls. When ea_name is set,
6037 * it looks for that attribute name and stuffs that value into the EAData
6038 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6039 * buffer. In both cases, the return value is either the length of the
6040 * resulting data or a negative error code. If EAData is a NULL pointer then
6041 * the data isn't copied to it, but the length is returned.
6042 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006044CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006045 const unsigned char *searchName, const unsigned char *ea_name,
6046 char *EAData, size_t buf_size,
6047 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048{
6049 /* BB assumes one setup word */
6050 TRANSACTION2_QPI_REQ *pSMB = NULL;
6051 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6052 int rc = 0;
6053 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006054 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006055 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006056 struct fea *temp_fea;
6057 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006058 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006059 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006060 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061
Joe Perchesf96637b2013-05-04 22:12:25 -05006062 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063QAllEAsRetry:
6064 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6065 (void **) &pSMBr);
6066 if (rc)
6067 return rc;
6068
6069 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006070 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006071 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6072 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006073 list_len++; /* trailing null */
6074 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006076 list_len = strnlen(searchName, PATH_MAX);
6077 list_len++; /* trailing null */
6078 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079 }
6080
Jeff Layton6e462b92010-02-10 16:18:26 -05006081 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 pSMB->TotalDataCount = 0;
6083 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006084 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006085 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 pSMB->MaxSetupCount = 0;
6087 pSMB->Reserved = 0;
6088 pSMB->Flags = 0;
6089 pSMB->Timeout = 0;
6090 pSMB->Reserved2 = 0;
6091 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006092 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 pSMB->DataCount = 0;
6094 pSMB->DataOffset = 0;
6095 pSMB->SetupCount = 1;
6096 pSMB->Reserved3 = 0;
6097 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6098 byte_count = params + 1 /* pad */ ;
6099 pSMB->TotalParameterCount = cpu_to_le16(params);
6100 pSMB->ParameterCount = pSMB->TotalParameterCount;
6101 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6102 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006103 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104 pSMB->ByteCount = cpu_to_le16(byte_count);
6105
6106 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6107 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6108 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006109 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006110 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006112
6113
6114 /* BB also check enough total bytes returned */
6115 /* BB we need to improve the validity checking
6116 of these trans2 responses */
6117
6118 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006119 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006120 rc = -EIO; /* bad smb */
6121 goto QAllEAsOut;
6122 }
6123
6124 /* check that length of list is not more than bcc */
6125 /* check that each entry does not go beyond length
6126 of list */
6127 /* check that each element of each entry does not
6128 go beyond end of list */
6129 /* validate_trans2_offsets() */
6130 /* BB check if start of smb + data_offset > &bcc+ bcc */
6131
6132 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6133 ea_response_data = (struct fealist *)
6134 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6135
Jeff Layton6e462b92010-02-10 16:18:26 -05006136 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006137 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006138 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006139 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006140 goto QAllEAsOut;
6141 }
6142
Jeff Layton0cd126b2010-02-10 16:18:26 -05006143 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006144 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006145 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006146 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006147 rc = -EIO;
6148 goto QAllEAsOut;
6149 }
6150
Jeff Laytonf0d38682010-02-10 16:18:26 -05006151 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006152 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006153 temp_fea = ea_response_data->list;
6154 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006155 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006156 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006157 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006158
Jeff Layton6e462b92010-02-10 16:18:26 -05006159 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006160 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006161 /* make sure we can read name_len and value_len */
6162 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006163 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006164 rc = -EIO;
6165 goto QAllEAsOut;
6166 }
6167
6168 name_len = temp_fea->name_len;
6169 value_len = le16_to_cpu(temp_fea->value_len);
6170 list_len -= name_len + 1 + 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
Jeff Layton31c05192010-02-10 16:18:26 -05006177 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006178 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006179 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006180 temp_ptr += name_len + 1;
6181 rc = value_len;
6182 if (buf_size == 0)
6183 goto QAllEAsOut;
6184 if ((size_t)value_len > buf_size) {
6185 rc = -ERANGE;
6186 goto QAllEAsOut;
6187 }
6188 memcpy(EAData, temp_ptr, value_len);
6189 goto QAllEAsOut;
6190 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006191 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006192 /* account for prefix user. and trailing null */
6193 rc += (5 + 1 + name_len);
6194 if (rc < (int) buf_size) {
6195 memcpy(EAData, "user.", 5);
6196 EAData += 5;
6197 memcpy(EAData, temp_ptr, name_len);
6198 EAData += name_len;
6199 /* null terminate name */
6200 *EAData = 0;
6201 ++EAData;
6202 } else if (buf_size == 0) {
6203 /* skip copy - calc size only */
6204 } else {
6205 /* stop before overrun buffer */
6206 rc = -ERANGE;
6207 break;
6208 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006209 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006210 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006211 temp_fea = (struct fea *)temp_ptr;
6212 }
6213
Jeff Layton31c05192010-02-10 16:18:26 -05006214 /* didn't find the named attribute */
6215 if (ea_name)
6216 rc = -ENODATA;
6217
Jeff Laytonf0d38682010-02-10 16:18:26 -05006218QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006219 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220 if (rc == -EAGAIN)
6221 goto QAllEAsRetry;
6222
6223 return (ssize_t)rc;
6224}
6225
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006227CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6228 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006229 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6230 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231{
6232 struct smb_com_transaction2_spi_req *pSMB = NULL;
6233 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6234 struct fealist *parm_data;
6235 int name_len;
6236 int rc = 0;
6237 int bytes_returned = 0;
6238 __u16 params, param_offset, byte_count, offset, count;
6239
Joe Perchesf96637b2013-05-04 22:12:25 -05006240 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241SetEARetry:
6242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6243 (void **) &pSMBr);
6244 if (rc)
6245 return rc;
6246
6247 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6248 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006249 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6250 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 name_len++; /* trailing null */
6252 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006253 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 name_len = strnlen(fileName, PATH_MAX);
6255 name_len++; /* trailing null */
6256 strncpy(pSMB->FileName, fileName, name_len);
6257 }
6258
6259 params = 6 + name_len;
6260
6261 /* done calculating parms using name_len of file name,
6262 now use name_len to calculate length of ea name
6263 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006264 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 name_len = 0;
6266 else
Steve French50c2f752007-07-13 00:33:32 +00006267 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006269 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006271 /* BB find max SMB PDU from sess */
6272 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273 pSMB->MaxSetupCount = 0;
6274 pSMB->Reserved = 0;
6275 pSMB->Flags = 0;
6276 pSMB->Timeout = 0;
6277 pSMB->Reserved2 = 0;
6278 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006279 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280 offset = param_offset + params;
6281 pSMB->InformationLevel =
6282 cpu_to_le16(SMB_SET_FILE_EA);
6283
6284 parm_data =
6285 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6286 offset);
6287 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6288 pSMB->DataOffset = cpu_to_le16(offset);
6289 pSMB->SetupCount = 1;
6290 pSMB->Reserved3 = 0;
6291 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6292 byte_count = 3 /* pad */ + params + count;
6293 pSMB->DataCount = cpu_to_le16(count);
6294 parm_data->list_len = cpu_to_le32(count);
6295 parm_data->list[0].EA_flags = 0;
6296 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006297 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006299 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006300 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301 parm_data->list[0].name[name_len] = 0;
6302 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6303 /* caller ensures that ea_value_len is less than 64K but
6304 we need to ensure that it fits within the smb */
6305
Steve French50c2f752007-07-13 00:33:32 +00006306 /*BB add length check to see if it would fit in
6307 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006308 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6309 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006310 memcpy(parm_data->list[0].name+name_len+1,
6311 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312
6313 pSMB->TotalDataCount = pSMB->DataCount;
6314 pSMB->ParameterCount = cpu_to_le16(params);
6315 pSMB->TotalParameterCount = pSMB->ParameterCount;
6316 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006317 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 pSMB->ByteCount = cpu_to_le16(byte_count);
6319 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6320 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006321 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006322 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323
6324 cifs_buf_release(pSMB);
6325
6326 if (rc == -EAGAIN)
6327 goto SetEARetry;
6328
6329 return rc;
6330}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331#endif
Steve French0eff0e22011-02-24 05:39:23 +00006332
6333#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6334/*
6335 * Years ago the kernel added a "dnotify" function for Samba server,
6336 * to allow network clients (such as Windows) to display updated
6337 * lists of files in directory listings automatically when
6338 * files are added by one user when another user has the
6339 * same directory open on their desktop. The Linux cifs kernel
6340 * client hooked into the kernel side of this interface for
6341 * the same reason, but ironically when the VFS moved from
6342 * "dnotify" to "inotify" it became harder to plug in Linux
6343 * network file system clients (the most obvious use case
6344 * for notify interfaces is when multiple users can update
6345 * the contents of the same directory - exactly what network
6346 * file systems can do) although the server (Samba) could
6347 * still use it. For the short term we leave the worker
6348 * function ifdeffed out (below) until inotify is fixed
6349 * in the VFS to make it easier to plug in network file
6350 * system clients. If inotify turns out to be permanently
6351 * incompatible for network fs clients, we could instead simply
6352 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6353 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006354int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006355 const int notify_subdirs, const __u16 netfid,
6356 __u32 filter, struct file *pfile, int multishot,
6357 const struct nls_table *nls_codepage)
6358{
6359 int rc = 0;
6360 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6361 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6362 struct dir_notify_req *dnotify_req;
6363 int bytes_returned;
6364
Joe Perchesf96637b2013-05-04 22:12:25 -05006365 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006366 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6367 (void **) &pSMBr);
6368 if (rc)
6369 return rc;
6370
6371 pSMB->TotalParameterCount = 0 ;
6372 pSMB->TotalDataCount = 0;
6373 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006374 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006375 pSMB->MaxSetupCount = 4;
6376 pSMB->Reserved = 0;
6377 pSMB->ParameterOffset = 0;
6378 pSMB->DataCount = 0;
6379 pSMB->DataOffset = 0;
6380 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6381 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6382 pSMB->ParameterCount = pSMB->TotalParameterCount;
6383 if (notify_subdirs)
6384 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6385 pSMB->Reserved2 = 0;
6386 pSMB->CompletionFilter = cpu_to_le32(filter);
6387 pSMB->Fid = netfid; /* file handle always le */
6388 pSMB->ByteCount = 0;
6389
6390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6391 (struct smb_hdr *)pSMBr, &bytes_returned,
6392 CIFS_ASYNC_OP);
6393 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006394 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006395 } else {
6396 /* Add file to outstanding requests */
6397 /* BB change to kmem cache alloc */
6398 dnotify_req = kmalloc(
6399 sizeof(struct dir_notify_req),
6400 GFP_KERNEL);
6401 if (dnotify_req) {
6402 dnotify_req->Pid = pSMB->hdr.Pid;
6403 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6404 dnotify_req->Mid = pSMB->hdr.Mid;
6405 dnotify_req->Tid = pSMB->hdr.Tid;
6406 dnotify_req->Uid = pSMB->hdr.Uid;
6407 dnotify_req->netfid = netfid;
6408 dnotify_req->pfile = pfile;
6409 dnotify_req->filter = filter;
6410 dnotify_req->multishot = multishot;
6411 spin_lock(&GlobalMid_Lock);
6412 list_add_tail(&dnotify_req->lhead,
6413 &GlobalDnotifyReqList);
6414 spin_unlock(&GlobalMid_Lock);
6415 } else
6416 rc = -ENOMEM;
6417 }
6418 cifs_buf_release(pSMB);
6419 return rc;
6420}
6421#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */