blob: b7e5b6508caafc3bc8397dde717e25dd505bdebf [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 Frencha45443472005-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 Frencha45443472005-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
Jeff Layton3f618222013-06-12 19:52:14 -0500371decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400372{
373 int rc = 0;
374 u16 count;
375 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500376 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400377
378 count = get_bcc(&pSMBr->hdr);
379 if (count < SMB1_CLIENT_GUID_SIZE)
380 return -EIO;
381
382 spin_lock(&cifs_tcp_ses_lock);
383 if (server->srv_count > 1) {
384 spin_unlock(&cifs_tcp_ses_lock);
385 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
386 cifs_dbg(FYI, "server UID changed\n");
387 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
388 }
389 } else {
390 spin_unlock(&cifs_tcp_ses_lock);
391 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
392 }
393
394 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500395 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400396 } else {
397 count -= SMB1_CLIENT_GUID_SIZE;
398 rc = decode_negTokenInit(
399 pSMBr->u.extended_response.SecurityBlob, count, server);
400 if (rc != 1)
401 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400402 }
403
404 return 0;
405}
406
Jeff Layton9ddec562013-05-26 07:00:58 -0400407int
Jeff Layton38d77c52013-05-26 07:01:00 -0400408cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400409{
Jeff Layton50285882013-06-27 12:45:00 -0400410 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
411 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400412 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
413
414 /*
415 * Is signing required by mnt options? If not then check
416 * global_secflags to see if it is there.
417 */
418 if (!mnt_sign_required)
419 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
420 CIFSSEC_MUST_SIGN);
421
422 /*
423 * If signing is required then it's automatically enabled too,
424 * otherwise, check to see if the secflags allow it.
425 */
426 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
427 (global_secflags & CIFSSEC_MAY_SIGN);
428
429 /* If server requires signing, does client allow it? */
430 if (srv_sign_required) {
431 if (!mnt_sign_enabled) {
432 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
433 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400434 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400435 server->sign = true;
436 }
437
438 /* If client requires signing, does server allow it? */
439 if (mnt_sign_required) {
440 if (!srv_sign_enabled) {
441 cifs_dbg(VFS, "Server does not support signing!");
442 return -ENOTSUPP;
443 }
444 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400445 }
446
447 return 0;
448}
449
Jeff Layton2190eca2013-05-26 07:00:57 -0400450#ifdef CONFIG_CIFS_WEAK_PW_HASH
451static int
Jeff Layton3f618222013-06-12 19:52:14 -0500452decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400453{
454 __s16 tmp;
455 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
456
457 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
458 return -EOPNOTSUPP;
459
Jeff Layton2190eca2013-05-26 07:00:57 -0400460 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
461 server->maxReq = min_t(unsigned int,
462 le16_to_cpu(rsp->MaxMpxCount),
463 cifs_max_pending);
464 set_credits(server, server->maxReq);
465 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400466 /* even though we do not use raw we might as well set this
467 accurately, in case we ever find a need for it */
468 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
469 server->max_rw = 0xFF00;
470 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
471 } else {
472 server->max_rw = 0;/* do not need to use raw anyway */
473 server->capabilities = CAP_MPX_MODE;
474 }
475 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
476 if (tmp == -1) {
477 /* OS/2 often does not set timezone therefore
478 * we must use server time to calc time zone.
479 * Could deviate slightly from the right zone.
480 * Smallest defined timezone difference is 15 minutes
481 * (i.e. Nepal). Rounding up/down is done to match
482 * this requirement.
483 */
484 int val, seconds, remain, result;
485 struct timespec ts, utc;
486 utc = CURRENT_TIME;
487 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
488 rsp->SrvTime.Time, 0);
489 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
490 (int)ts.tv_sec, (int)utc.tv_sec,
491 (int)(utc.tv_sec - ts.tv_sec));
492 val = (int)(utc.tv_sec - ts.tv_sec);
493 seconds = abs(val);
494 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
495 remain = seconds % MIN_TZ_ADJ;
496 if (remain >= (MIN_TZ_ADJ / 2))
497 result += MIN_TZ_ADJ;
498 if (val < 0)
499 result = -result;
500 server->timeAdj = result;
501 } else {
502 server->timeAdj = (int)tmp;
503 server->timeAdj *= 60; /* also in seconds */
504 }
505 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
506
507
508 /* BB get server time for time conversions and add
509 code to use it and timezone since this is not UTC */
510
511 if (rsp->EncryptionKeyLength ==
512 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
513 memcpy(server->cryptkey, rsp->EncryptionKey,
514 CIFS_CRYPTO_KEY_SIZE);
515 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
516 return -EIO; /* need cryptkey unless plain text */
517 }
518
519 cifs_dbg(FYI, "LANMAN negotiated\n");
520 return 0;
521}
522#else
523static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500524decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400525{
526 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
527 return -EOPNOTSUPP;
528}
529#endif
530
Jeff Layton91934002013-05-26 07:00:58 -0400531static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500532should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400533{
Jeff Layton3f618222013-06-12 19:52:14 -0500534 switch (sectype) {
535 case RawNTLMSSP:
536 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400537 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500538 case Unspecified:
539 if (global_secflags &
540 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
541 return true;
542 /* Fallthrough */
543 default:
544 return false;
545 }
Jeff Layton91934002013-05-26 07:00:58 -0400546}
547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400549CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
551 NEGOTIATE_REQ *pSMB;
552 NEGOTIATE_RSP *pSMBr;
553 int rc = 0;
554 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000555 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400556 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 u16 count;
558
Jeff Layton3534b852013-05-24 07:41:01 -0400559 if (!server) {
560 WARN(1, "%s: server is NULL!\n", __func__);
561 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
Jeff Layton3534b852013-05-24 07:41:01 -0400563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
565 (void **) &pSMB, (void **) &pSMBr);
566 if (rc)
567 return rc;
Steve French750d1152006-06-27 06:28:30 +0000568
Pavel Shilovsky88257362012-05-23 14:01:59 +0400569 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000570 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000571
Jeff Layton3f618222013-06-12 19:52:14 -0500572 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400573 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000574 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
575 }
Steve French50c2f752007-07-13 00:33:32 +0000576
Steve French39798772006-05-31 22:40:51 +0000577 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000578 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000579 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
580 count += strlen(protocols[i].name) + 1;
581 /* null at end of source and target buffers anyway */
582 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000583 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 pSMB->ByteCount = cpu_to_le16(count);
585
586 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
587 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000588 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000589 goto neg_err_exit;
590
Jeff Layton9bf67e52010-04-24 07:57:46 -0400591 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500592 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000593 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400594 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000595 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000596 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000597 could not negotiate a common dialect */
598 rc = -EOPNOTSUPP;
599 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000600 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400601 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500602 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400603 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000604 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000605 /* unknown wct */
606 rc = -EOPNOTSUPP;
607 goto neg_err_exit;
608 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400609 /* else wct == 17, NTLM or better */
610
Steve French96daf2b2011-05-27 04:34:02 +0000611 server->sec_mode = pSMBr->SecurityMode;
612 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500613 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000614
Steve French254e55e2006-06-04 05:53:15 +0000615 /* one byte, so no need to convert this or EncryptionKeyLen from
616 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300617 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
618 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400619 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000620 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400621 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000622 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500623 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000624 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000625 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
626 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400627
Jeff Laytone598d1d82013-05-26 07:00:59 -0400628 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
629 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500630 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000631 CIFS_CRYPTO_KEY_SIZE);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400632 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000633 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Laytone598d1d82013-05-26 07:00:59 -0400634 (pSMBr->EncryptionKeyLength == 0)) {
635 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500636 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400637 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000638 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400639 } else {
640 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000641 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400642 }
Steve French254e55e2006-06-04 05:53:15 +0000643
644signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400645 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400646 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000647neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700648 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000649
Joe Perchesf96637b2013-05-04 22:12:25 -0500650 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return rc;
652}
653
654int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400655CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Joe Perchesf96637b2013-05-04 22:12:25 -0500660 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500661
662 /* BB: do we need to check this? These should never be NULL. */
663 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
664 return -EIO;
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500667 * No need to return error on this operation if tid invalidated and
668 * closed on server already e.g. due to tcp session crashing. Also,
669 * the tcon is no longer on the list, so no need to take lock before
670 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 */
Steve French268875b2009-06-25 00:29:21 +0000672 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000673 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Steve French50c2f752007-07-13 00:33:32 +0000675 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700676 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500677 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 return rc;
Steve French133672e2007-11-13 22:41:37 +0000679
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400680 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500682 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Steve French50c2f752007-07-13 00:33:32 +0000684 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500685 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (rc == -EAGAIN)
687 rc = 0;
688
689 return rc;
690}
691
Jeff Layton766fdbb2011-01-11 07:24:21 -0500692/*
693 * This is a no-op for now. We're not really interested in the reply, but
694 * rather in the fact that the server sent one and that server->lstrp
695 * gets updated.
696 *
697 * FIXME: maybe we should consider checking that the reply matches request?
698 */
699static void
700cifs_echo_callback(struct mid_q_entry *mid)
701{
702 struct TCP_Server_Info *server = mid->callback_data;
703
704 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400705 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706}
707
708int
709CIFSSMBEcho(struct TCP_Server_Info *server)
710{
711 ECHO_REQ *smb;
712 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400713 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700714 struct smb_rqst rqst = { .rq_iov = &iov,
715 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500716
Joe Perchesf96637b2013-05-04 22:12:25 -0500717 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500718
719 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
720 if (rc)
721 return rc;
722
723 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000724 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500725 smb->hdr.WordCount = 1;
726 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400727 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500728 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000729 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400730 iov.iov_base = smb;
731 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500732
Jeff Laytonfec344e2012-09-18 16:20:35 -0700733 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400734 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500735 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500736 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737
738 cifs_small_buf_release(smb);
739
740 return rc;
741}
742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400744CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 LOGOFF_ANDX_REQ *pSMB;
747 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Joe Perchesf96637b2013-05-04 22:12:25 -0500749 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500750
751 /*
752 * BB: do we need to check validity of ses and server? They should
753 * always be valid since we have an active reference. If not, that
754 * should probably be a BUG()
755 */
756 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return -EIO;
758
Steve Frenchd7b619c2010-02-25 05:36:46 +0000759 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000760 if (ses->need_reconnect)
761 goto session_already_dead; /* no need to send SMBlogoff if uid
762 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
764 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000765 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return rc;
767 }
768
Pavel Shilovsky88257362012-05-23 14:01:59 +0400769 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700770
Jeff Layton38d77c52013-05-26 07:01:00 -0400771 if (ses->server->sign)
772 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774 pSMB->hdr.Uid = ses->Suid;
775
776 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400777 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000778session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000779 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000782 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 error */
784 if (rc == -EAGAIN)
785 rc = 0;
786 return rc;
787}
788
789int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400790CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
791 const char *fileName, __u16 type,
792 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000793{
794 TRANSACTION2_SPI_REQ *pSMB = NULL;
795 TRANSACTION2_SPI_RSP *pSMBr = NULL;
796 struct unlink_psx_rq *pRqD;
797 int name_len;
798 int rc = 0;
799 int bytes_returned = 0;
800 __u16 params, param_offset, offset, byte_count;
801
Joe Perchesf96637b2013-05-04 22:12:25 -0500802 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000803PsxDelete:
804 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
805 (void **) &pSMBr);
806 if (rc)
807 return rc;
808
809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
810 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600811 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
812 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000813 name_len++; /* trailing null */
814 name_len *= 2;
815 } else { /* BB add path length overrun check */
816 name_len = strnlen(fileName, PATH_MAX);
817 name_len++; /* trailing null */
818 strncpy(pSMB->FileName, fileName, name_len);
819 }
820
821 params = 6 + name_len;
822 pSMB->MaxParameterCount = cpu_to_le16(2);
823 pSMB->MaxDataCount = 0; /* BB double check this with jra */
824 pSMB->MaxSetupCount = 0;
825 pSMB->Reserved = 0;
826 pSMB->Flags = 0;
827 pSMB->Timeout = 0;
828 pSMB->Reserved2 = 0;
829 param_offset = offsetof(struct smb_com_transaction2_spi_req,
830 InformationLevel) - 4;
831 offset = param_offset + params;
832
833 /* Setup pointer to Request Data (inode type) */
834 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
835 pRqD->type = cpu_to_le16(type);
836 pSMB->ParameterOffset = cpu_to_le16(param_offset);
837 pSMB->DataOffset = cpu_to_le16(offset);
838 pSMB->SetupCount = 1;
839 pSMB->Reserved3 = 0;
840 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
841 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
842
843 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
844 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
845 pSMB->ParameterCount = cpu_to_le16(params);
846 pSMB->TotalParameterCount = pSMB->ParameterCount;
847 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
848 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000849 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000850 pSMB->ByteCount = cpu_to_le16(byte_count);
851 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
852 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000853 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500854 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000855 cifs_buf_release(pSMB);
856
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400857 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000858
859 if (rc == -EAGAIN)
860 goto PsxDelete;
861
862 return rc;
863}
864
865int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700866CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
867 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
869 DELETE_FILE_REQ *pSMB = NULL;
870 DELETE_FILE_RSP *pSMBr = NULL;
871 int rc = 0;
872 int bytes_returned;
873 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700874 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
876DelFileRetry:
877 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
878 (void **) &pSMBr);
879 if (rc)
880 return rc;
881
882 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700883 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
884 PATH_MAX, cifs_sb->local_nls,
885 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 name_len++; /* trailing null */
887 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700888 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700889 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700891 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 }
893 pSMB->SearchAttributes =
894 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
895 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000896 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 pSMB->ByteCount = cpu_to_le16(name_len + 1);
898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400900 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000901 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500902 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
904 cifs_buf_release(pSMB);
905 if (rc == -EAGAIN)
906 goto DelFileRetry;
907
908 return rc;
909}
910
911int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400912CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
913 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
915 DELETE_DIRECTORY_REQ *pSMB = NULL;
916 DELETE_DIRECTORY_RSP *pSMBr = NULL;
917 int rc = 0;
918 int bytes_returned;
919 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400920 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Joe Perchesf96637b2013-05-04 22:12:25 -0500922 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923RmDirRetry:
924 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
925 (void **) &pSMBr);
926 if (rc)
927 return rc;
928
929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400930 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
931 PATH_MAX, cifs_sb->local_nls,
932 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 name_len++; /* trailing null */
934 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700935 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400936 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400938 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 }
940
941 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000942 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 pSMB->ByteCount = cpu_to_le16(name_len + 1);
944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400946 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000947 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500948 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 cifs_buf_release(pSMB);
951 if (rc == -EAGAIN)
952 goto RmDirRetry;
953 return rc;
954}
955
956int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300957CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
958 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
960 int rc = 0;
961 CREATE_DIRECTORY_REQ *pSMB = NULL;
962 CREATE_DIRECTORY_RSP *pSMBr = NULL;
963 int bytes_returned;
964 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300965 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Joe Perchesf96637b2013-05-04 22:12:25 -0500967 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968MkDirRetry:
969 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
970 (void **) &pSMBr);
971 if (rc)
972 return rc;
973
974 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600975 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300976 PATH_MAX, cifs_sb->local_nls,
977 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 name_len++; /* trailing null */
979 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700980 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 name_len = strnlen(name, PATH_MAX);
982 name_len++; /* trailing null */
983 strncpy(pSMB->DirName, name, name_len);
984 }
985
986 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000987 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 pSMB->ByteCount = cpu_to_le16(name_len + 1);
989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400991 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000992 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500993 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 cifs_buf_release(pSMB);
996 if (rc == -EAGAIN)
997 goto MkDirRetry;
998 return rc;
999}
1000
Steve French2dd29d32007-04-23 22:07:35 +00001001int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001002CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1003 __u32 posix_flags, __u64 mode, __u16 *netfid,
1004 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1005 const char *name, const struct nls_table *nls_codepage,
1006 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001007{
1008 TRANSACTION2_SPI_REQ *pSMB = NULL;
1009 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1010 int name_len;
1011 int rc = 0;
1012 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001013 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001014 OPEN_PSX_REQ *pdata;
1015 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001016
Joe Perchesf96637b2013-05-04 22:12:25 -05001017 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001018PsxCreat:
1019 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1020 (void **) &pSMBr);
1021 if (rc)
1022 return rc;
1023
1024 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1025 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001026 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1027 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001028 name_len++; /* trailing null */
1029 name_len *= 2;
1030 } else { /* BB improve the check for buffer overruns BB */
1031 name_len = strnlen(name, PATH_MAX);
1032 name_len++; /* trailing null */
1033 strncpy(pSMB->FileName, name, name_len);
1034 }
1035
1036 params = 6 + name_len;
1037 count = sizeof(OPEN_PSX_REQ);
1038 pSMB->MaxParameterCount = cpu_to_le16(2);
1039 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1040 pSMB->MaxSetupCount = 0;
1041 pSMB->Reserved = 0;
1042 pSMB->Flags = 0;
1043 pSMB->Timeout = 0;
1044 pSMB->Reserved2 = 0;
1045 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001046 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001047 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001048 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001049 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001050 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001051 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001052 pdata->OpenFlags = cpu_to_le32(*pOplock);
1053 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1054 pSMB->DataOffset = cpu_to_le16(offset);
1055 pSMB->SetupCount = 1;
1056 pSMB->Reserved3 = 0;
1057 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1058 byte_count = 3 /* pad */ + params + count;
1059
1060 pSMB->DataCount = cpu_to_le16(count);
1061 pSMB->ParameterCount = cpu_to_le16(params);
1062 pSMB->TotalDataCount = pSMB->DataCount;
1063 pSMB->TotalParameterCount = pSMB->ParameterCount;
1064 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1065 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001066 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001067 pSMB->ByteCount = cpu_to_le16(byte_count);
1068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1070 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001071 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001072 goto psx_create_err;
1073 }
1074
Joe Perchesf96637b2013-05-04 22:12:25 -05001075 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1077
Jeff Layton820a8032011-05-04 08:05:26 -04001078 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001079 rc = -EIO; /* bad smb */
1080 goto psx_create_err;
1081 }
1082
1083 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001084 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001085 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001086
Steve French2dd29d32007-04-23 22:07:35 +00001087 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001088 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001089 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1090 /* Let caller know file was created so we can set the mode. */
1091 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001092 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001093 *pOplock |= CIFS_CREATE_ACTION;
1094 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001095 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1096 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001097 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001098 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001099 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001100 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001101 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001103 goto psx_create_err;
1104 }
Steve French50c2f752007-07-13 00:33:32 +00001105 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001106 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001107 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001108 }
Steve French2dd29d32007-04-23 22:07:35 +00001109
1110psx_create_err:
1111 cifs_buf_release(pSMB);
1112
Steve French65bc98b2009-07-10 15:27:25 +00001113 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001114 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001115 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001116 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001117
1118 if (rc == -EAGAIN)
1119 goto PsxCreat;
1120
Steve French50c2f752007-07-13 00:33:32 +00001121 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001122}
1123
Steve Frencha9d02ad2005-08-24 23:06:05 -07001124static __u16 convert_disposition(int disposition)
1125{
1126 __u16 ofun = 0;
1127
1128 switch (disposition) {
1129 case FILE_SUPERSEDE:
1130 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1131 break;
1132 case FILE_OPEN:
1133 ofun = SMBOPEN_OAPPEND;
1134 break;
1135 case FILE_CREATE:
1136 ofun = SMBOPEN_OCREATE;
1137 break;
1138 case FILE_OPEN_IF:
1139 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_OVERWRITE:
1142 ofun = SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OVERWRITE_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001148 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001149 ofun = SMBOPEN_OAPPEND; /* regular open */
1150 }
1151 return ofun;
1152}
1153
Jeff Layton35fc37d2008-05-14 10:22:03 -07001154static int
1155access_flags_to_smbopen_mode(const int access_flags)
1156{
1157 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1158
1159 if (masked_flags == GENERIC_READ)
1160 return SMBOPEN_READ;
1161 else if (masked_flags == GENERIC_WRITE)
1162 return SMBOPEN_WRITE;
1163
1164 /* just go for read/write */
1165 return SMBOPEN_READWRITE;
1166}
1167
Steve Frencha9d02ad2005-08-24 23:06:05 -07001168int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001169SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001171 const int access_flags, const int create_options, __u16 *netfid,
1172 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 const struct nls_table *nls_codepage, int remap)
1174{
1175 int rc = -EACCES;
1176 OPENX_REQ *pSMB = NULL;
1177 OPENX_RSP *pSMBr = NULL;
1178 int bytes_returned;
1179 int name_len;
1180 __u16 count;
1181
1182OldOpenRetry:
1183 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1184 (void **) &pSMBr);
1185 if (rc)
1186 return rc;
1187
1188 pSMB->AndXCommand = 0xFF; /* none */
1189
1190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1191 count = 1; /* account for one byte pad to word boundary */
1192 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001193 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1194 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001195 name_len++; /* trailing null */
1196 name_len *= 2;
1197 } else { /* BB improve check for buffer overruns BB */
1198 count = 0; /* no pad */
1199 name_len = strnlen(fileName, PATH_MAX);
1200 name_len++; /* trailing null */
1201 strncpy(pSMB->fileName, fileName, name_len);
1202 }
1203 if (*pOplock & REQ_OPLOCK)
1204 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001205 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001207
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001209 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1211 /* set file as system file if special file such
1212 as fifo and server expecting SFU style and
1213 no Unix extensions */
1214
Steve French790fe572007-07-07 19:25:05 +00001215 if (create_options & CREATE_OPTION_SPECIAL)
1216 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001217 else /* BB FIXME BB */
1218 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219
Jeff Layton67750fb2008-05-09 22:28:02 +00001220 if (create_options & CREATE_OPTION_READONLY)
1221 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222
1223 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001224/* pSMB->CreateOptions = cpu_to_le32(create_options &
1225 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001227
1228 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001229 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001231 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232
1233 pSMB->ByteCount = cpu_to_le16(count);
1234 /* long_op set to 1 to allow for oplock break timeouts */
1235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001236 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001237 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001239 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 } else {
1241 /* BB verify if wct == 15 */
1242
Steve French582d21e2008-05-13 04:54:12 +00001243/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244
1245 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1246 /* Let caller know file was created so we can set the mode. */
1247 /* Do we care about the CreateAction in any other cases? */
1248 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001249/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 *pOplock |= CIFS_CREATE_ACTION; */
1251 /* BB FIXME END */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255 pfile_info->LastAccessTime = 0; /* BB fixme */
1256 pfile_info->LastWriteTime = 0; /* BB fixme */
1257 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001258 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001259 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001261 pfile_info->AllocationSize =
1262 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001265 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 }
1267 }
1268
1269 cifs_buf_release(pSMB);
1270 if (rc == -EAGAIN)
1271 goto OldOpenRetry;
1272 return rc;
1273}
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001276CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1277 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
1279 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001280 OPEN_REQ *req = NULL;
1281 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 int bytes_returned;
1283 int name_len;
1284 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001285 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1286 struct cifs_tcon *tcon = oparms->tcon;
1287 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
1288 const struct nls_table *nls = cifs_sb->local_nls;
1289 int create_options = oparms->create_options;
1290 int desired_access = oparms->desired_access;
1291 int disposition = oparms->disposition;
1292 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
1294openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001295 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1296 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (rc)
1298 return rc;
1299
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001300 /* no commands go after this */
1301 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001303 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1304 /* account for one byte pad to word boundary */
1305 count = 1;
1306 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1307 path, PATH_MAX, nls, remap);
1308 /* trailing null */
1309 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001311 req->NameLength = cpu_to_le16(name_len);
1312 } else {
1313 /* BB improve check for buffer overruns BB */
1314 /* no pad */
1315 count = 0;
1316 name_len = strnlen(path, PATH_MAX);
1317 /* trailing null */
1318 name_len++;
1319 req->NameLength = cpu_to_le16(name_len);
1320 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001322
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001323 if (*oplock & REQ_OPLOCK)
1324 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1325 else if (*oplock & REQ_BATCHOPLOCK)
1326 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1327
1328 req->DesiredAccess = cpu_to_le32(desired_access);
1329 req->AllocationSize = 0;
1330
1331 /*
1332 * Set file as system file if special file such as fifo and server
1333 * expecting SFU style and no Unix extensions.
1334 */
1335 if (create_options & CREATE_OPTION_SPECIAL)
1336 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1337 else
1338 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1339
1340 /*
1341 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1342 * sensitive checks for other servers such as Samba.
1343 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001345 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Jeff Layton67750fb2008-05-09 22:28:02 +00001347 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001348 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001349
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001350 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1351 req->CreateDisposition = cpu_to_le32(disposition);
1352 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1353
Steve French09d1db52005-04-28 22:41:08 -07001354 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001355 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1356 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001359 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001361 req->ByteCount = cpu_to_le16(count);
1362 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1363 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001364 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001366 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001367 cifs_buf_release(req);
1368 if (rc == -EAGAIN)
1369 goto openRetry;
1370 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001372
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001373 /* 1 byte no need to le_to_cpu */
1374 *oplock = rsp->OplockLevel;
1375 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001376 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001377
1378 /* Let caller know file was created so we can set the mode. */
1379 /* Do we care about the CreateAction in any other cases? */
1380 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1381 *oplock |= CIFS_CREATE_ACTION;
1382
1383 if (buf) {
1384 /* copy from CreationTime to Attributes */
1385 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1386 /* the file_info buf is endian converted by caller */
1387 buf->AllocationSize = rsp->AllocationSize;
1388 buf->EndOfFile = rsp->EndOfFile;
1389 buf->NumberOfLinks = cpu_to_le32(1);
1390 buf->DeletePending = 0;
1391 }
1392
1393 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 return rc;
1395}
1396
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001397/*
1398 * Discard any remaining data in the current SMB. To do this, we borrow the
1399 * current bigbuf.
1400 */
1401static int
1402cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1403{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001404 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001405 int remaining = rfclen + 4 - server->total_read;
1406 struct cifs_readdata *rdata = mid->callback_data;
1407
1408 while (remaining > 0) {
1409 int length;
1410
1411 length = cifs_read_from_socket(server, server->bigbuf,
1412 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001413 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001414 if (length < 0)
1415 return length;
1416 server->total_read += length;
1417 remaining -= length;
1418 }
1419
1420 dequeue_mid(mid, rdata->result);
1421 return 0;
1422}
1423
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001424int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1426{
1427 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001428 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001430 char *buf = server->smallbuf;
1431 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432
Joe Perchesf96637b2013-05-04 22:12:25 -05001433 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1434 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001435
1436 /*
1437 * read the rest of READ_RSP header (sans Data array), or whatever we
1438 * can if there's not enough data. At this point, we've read down to
1439 * the Mid.
1440 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001441 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001442 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443
Jeff Layton58195752012-09-19 06:22:34 -07001444 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1445 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446
Jeff Layton58195752012-09-19 06:22:34 -07001447 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448 if (length < 0)
1449 return length;
1450 server->total_read += length;
1451
1452 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001453 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001454 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001455 cifs_dbg(FYI, "%s: server returned error %d\n",
1456 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 return cifs_readv_discard(server, mid);
1458 }
1459
1460 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001461 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001462 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1463 __func__, server->total_read,
1464 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 rdata->result = -EIO;
1466 return cifs_readv_discard(server, mid);
1467 }
1468
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001469 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001470 if (data_offset < server->total_read) {
1471 /*
1472 * win2k8 sometimes sends an offset of 0 when the read
1473 * is beyond the EOF. Treat it as if the data starts just after
1474 * the header.
1475 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001476 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1477 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001478 data_offset = server->total_read;
1479 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1480 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001481 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1482 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001483 rdata->result = -EIO;
1484 return cifs_readv_discard(server, mid);
1485 }
1486
Joe Perchesf96637b2013-05-04 22:12:25 -05001487 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1488 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489
1490 len = data_offset - server->total_read;
1491 if (len > 0) {
1492 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001493 rdata->iov.iov_base = buf + server->total_read;
1494 rdata->iov.iov_len = len;
1495 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001496 if (length < 0)
1497 return length;
1498 server->total_read += length;
1499 }
1500
1501 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001502 rdata->iov.iov_base = buf;
1503 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001504 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1505 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506
1507 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001508 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001509 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001510 /* data_len is corrupt -- discard frame */
1511 rdata->result = -EIO;
1512 return cifs_readv_discard(server, mid);
1513 }
1514
Jeff Layton8321fec2012-09-19 06:22:32 -07001515 length = rdata->read_into_pages(server, rdata, data_len);
1516 if (length < 0)
1517 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001518
Jeff Layton8321fec2012-09-19 06:22:32 -07001519 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520 rdata->bytes = length;
1521
Joe Perchesf96637b2013-05-04 22:12:25 -05001522 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1523 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524
1525 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001526 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001527 return cifs_readv_discard(server, mid);
1528
1529 dequeue_mid(mid, false);
1530 return length;
1531}
1532
1533static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001534cifs_readv_callback(struct mid_q_entry *mid)
1535{
1536 struct cifs_readdata *rdata = mid->callback_data;
1537 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1538 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001539 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1540 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001541 .rq_pages = rdata->pages,
1542 .rq_npages = rdata->nr_pages,
1543 .rq_pagesz = rdata->pagesz,
1544 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545
Joe Perchesf96637b2013-05-04 22:12:25 -05001546 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1547 __func__, mid->mid, mid->mid_state, rdata->result,
1548 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001550 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001551 case MID_RESPONSE_RECEIVED:
1552 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001553 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001554 int rc = 0;
1555
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001556 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001557 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001558 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001559 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1560 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001561 }
1562 /* FIXME: should this be counted toward the initiating task? */
1563 task_io_account_read(rdata->bytes);
1564 cifs_stats_bytes_read(tcon, rdata->bytes);
1565 break;
1566 case MID_REQUEST_SUBMITTED:
1567 case MID_RETRY_NEEDED:
1568 rdata->result = -EAGAIN;
1569 break;
1570 default:
1571 rdata->result = -EIO;
1572 }
1573
Jeff Laytonda472fc2012-03-23 14:40:53 -04001574 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001575 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001576 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577}
1578
1579/* cifs_async_readv - send an async write, and set up mid to handle result */
1580int
1581cifs_async_readv(struct cifs_readdata *rdata)
1582{
1583 int rc;
1584 READ_REQ *smb = NULL;
1585 int wct;
1586 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001587 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001588 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001589
Joe Perchesf96637b2013-05-04 22:12:25 -05001590 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1591 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001592
1593 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1594 wct = 12;
1595 else {
1596 wct = 10; /* old style read */
1597 if ((rdata->offset >> 32) > 0) {
1598 /* can not handle this big offset for old */
1599 return -EIO;
1600 }
1601 }
1602
1603 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1604 if (rc)
1605 return rc;
1606
1607 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1608 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1609
1610 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001611 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001612 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1613 if (wct == 12)
1614 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1615 smb->Remaining = 0;
1616 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1617 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1618 if (wct == 12)
1619 smb->ByteCount = 0;
1620 else {
1621 /* old style read */
1622 struct smb_com_readx_req *smbr =
1623 (struct smb_com_readx_req *)smb;
1624 smbr->ByteCount = 0;
1625 }
1626
1627 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001628 rdata->iov.iov_base = smb;
1629 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630
Jeff Layton6993f742012-05-16 07:13:17 -04001631 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001632 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1633 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001634
1635 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001636 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001637 else
1638 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001639
1640 cifs_small_buf_release(smb);
1641 return rc;
1642}
1643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001645CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1646 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
1648 int rc = -EACCES;
1649 READ_REQ *pSMB = NULL;
1650 READ_RSP *pSMBr = NULL;
1651 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001652 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001653 int resp_buf_type = 0;
1654 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001655 __u32 pid = io_parms->pid;
1656 __u16 netfid = io_parms->netfid;
1657 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001658 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001659 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
Joe Perchesf96637b2013-05-04 22:12:25 -05001661 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001662 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001663 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001664 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001665 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001666 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001667 /* can not handle this big offset for old */
1668 return -EIO;
1669 }
1670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001673 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 if (rc)
1675 return rc;
1676
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001677 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1678 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1679
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 /* tcon and ses pointer are checked in smb_init */
1681 if (tcon->ses->server == NULL)
1682 return -ECONNABORTED;
1683
Steve Frenchec637e32005-12-12 20:53:18 -08001684 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001686 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001687 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001688 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001689
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 pSMB->Remaining = 0;
1691 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1692 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001693 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001694 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1695 else {
1696 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001697 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001698 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001699 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001700 }
Steve Frenchec637e32005-12-12 20:53:18 -08001701
1702 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001703 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001704 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001705 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001706 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001707 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001709 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 } else {
1711 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1712 data_length = data_length << 16;
1713 data_length += le16_to_cpu(pSMBr->DataLength);
1714 *nbytes = data_length;
1715
1716 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001717 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001719 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001720 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 rc = -EIO;
1722 *nbytes = 0;
1723 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001724 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001725 le16_to_cpu(pSMBr->DataOffset);
1726/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001727 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001728 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001729 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001730 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001731 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 }
1733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
Steve French4b8f9302006-02-26 16:41:18 +00001735/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001736 if (*buf) {
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01001737 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001738 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001739 /* return buffer to caller to free */
1740 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001741 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001742 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001743 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001744 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001745 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001746
1747 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 since file handle passed in no longer valid */
1749 return rc;
1750}
1751
Steve Frenchec637e32005-12-12 20:53:18 -08001752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001754CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001755 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001756 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757{
1758 int rc = -EACCES;
1759 WRITE_REQ *pSMB = NULL;
1760 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001761 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 __u32 bytes_sent;
1763 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001764 __u32 pid = io_parms->pid;
1765 __u16 netfid = io_parms->netfid;
1766 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001767 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001768 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
Steve Frencha24e2d72010-04-03 17:20:21 +00001770 *nbytes = 0;
1771
Joe Perchesf96637b2013-05-04 22:12:25 -05001772 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001773 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001774 return -ECONNABORTED;
1775
Steve French790fe572007-07-07 19:25:05 +00001776 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001777 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001778 else {
Steve French1c955182005-08-30 20:58:07 -07001779 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001780 if ((offset >> 32) > 0) {
1781 /* can not handle big offset for old srv */
1782 return -EIO;
1783 }
1784 }
Steve French1c955182005-08-30 20:58:07 -07001785
1786 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 (void **) &pSMBr);
1788 if (rc)
1789 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001790
1791 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1792 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1793
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 /* tcon and ses pointer are checked in smb_init */
1795 if (tcon->ses->server == NULL)
1796 return -ECONNABORTED;
1797
1798 pSMB->AndXCommand = 0xFF; /* none */
1799 pSMB->Fid = netfid;
1800 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001801 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001802 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 pSMB->Reserved = 0xFFFFFFFF;
1805 pSMB->WriteMode = 0;
1806 pSMB->Remaining = 0;
1807
Steve French50c2f752007-07-13 00:33:32 +00001808 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 can send more if LARGE_WRITE_X capability returned by the server and if
1810 our buffer is big enough or if we convert to iovecs on socket writes
1811 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001812 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1814 } else {
1815 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1816 & ~0xFF;
1817 }
1818
1819 if (bytes_sent > count)
1820 bytes_sent = count;
1821 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001822 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001823 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001824 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001825 else if (ubuf) {
1826 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 cifs_buf_release(pSMB);
1828 return -EFAULT;
1829 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001830 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 /* No buffer */
1832 cifs_buf_release(pSMB);
1833 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001834 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001835 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001836 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001837 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001838 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1841 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001842 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001843
Steve French790fe572007-07-07 19:25:05 +00001844 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001845 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001846 else { /* old style write has byte count 4 bytes earlier
1847 so 4 bytes pad */
1848 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001849 (struct smb_com_writex_req *)pSMB;
1850 pSMBW->ByteCount = cpu_to_le16(byte_count);
1851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1854 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001855 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001857 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 } else {
1859 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1860 *nbytes = (*nbytes) << 16;
1861 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301862
1863 /*
1864 * Mask off high 16 bits when bytes written as returned by the
1865 * server is greater than bytes requested by the client. Some
1866 * OS/2 servers are known to set incorrect CountHigh values.
1867 */
1868 if (*nbytes > count)
1869 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 }
1871
1872 cifs_buf_release(pSMB);
1873
Steve French50c2f752007-07-13 00:33:32 +00001874 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 since file handle passed in no longer valid */
1876
1877 return rc;
1878}
1879
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001880void
1881cifs_writedata_release(struct kref *refcount)
1882{
1883 struct cifs_writedata *wdata = container_of(refcount,
1884 struct cifs_writedata, refcount);
1885
1886 if (wdata->cfile)
1887 cifsFileInfo_put(wdata->cfile);
1888
1889 kfree(wdata);
1890}
1891
1892/*
1893 * Write failed with a retryable error. Resend the write request. It's also
1894 * possible that the page was redirtied so re-clean the page.
1895 */
1896static void
1897cifs_writev_requeue(struct cifs_writedata *wdata)
1898{
1899 int i, rc;
1900 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001901 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001902
1903 for (i = 0; i < wdata->nr_pages; i++) {
1904 lock_page(wdata->pages[i]);
1905 clear_page_dirty_for_io(wdata->pages[i]);
1906 }
1907
1908 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001909 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
Steve French4a5c80d2014-02-07 20:45:12 -06001910 rc = server->ops->async_writev(wdata, cifs_writedata_release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001911 } while (rc == -EAGAIN);
1912
1913 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001914 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001915 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001916 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001917 end_page_writeback(wdata->pages[i]);
1918 page_cache_release(wdata->pages[i]);
1919 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001920 }
1921
1922 mapping_set_error(inode->i_mapping, rc);
1923 kref_put(&wdata->refcount, cifs_writedata_release);
1924}
1925
Jeff Laytonc2e87642012-03-23 14:40:55 -04001926void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001927cifs_writev_complete(struct work_struct *work)
1928{
1929 struct cifs_writedata *wdata = container_of(work,
1930 struct cifs_writedata, work);
1931 struct inode *inode = wdata->cfile->dentry->d_inode;
1932 int i = 0;
1933
1934 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001935 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001936 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001937 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001938 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1939 wdata->bytes);
1940 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1941 return cifs_writev_requeue(wdata);
1942
1943 for (i = 0; i < wdata->nr_pages; i++) {
1944 struct page *page = wdata->pages[i];
1945 if (wdata->result == -EAGAIN)
1946 __set_page_dirty_nobuffers(page);
1947 else if (wdata->result < 0)
1948 SetPageError(page);
1949 end_page_writeback(page);
1950 page_cache_release(page);
1951 }
1952 if (wdata->result != -EAGAIN)
1953 mapping_set_error(inode->i_mapping, wdata->result);
1954 kref_put(&wdata->refcount, cifs_writedata_release);
1955}
1956
1957struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001958cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001959{
1960 struct cifs_writedata *wdata;
1961
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001962 /* writedata + number of page pointers */
1963 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05001964 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001965 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001966 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001967 INIT_LIST_HEAD(&wdata->list);
1968 init_completion(&wdata->done);
1969 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001970 }
1971 return wdata;
1972}
1973
1974/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001975 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976 * workqueue completion task.
1977 */
1978static void
1979cifs_writev_callback(struct mid_q_entry *mid)
1980{
1981 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001982 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001983 unsigned int written;
1984 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1985
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001986 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001987 case MID_RESPONSE_RECEIVED:
1988 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1989 if (wdata->result != 0)
1990 break;
1991
1992 written = le16_to_cpu(smb->CountHigh);
1993 written <<= 16;
1994 written += le16_to_cpu(smb->Count);
1995 /*
1996 * Mask off high 16 bits when bytes written as returned
1997 * by the server is greater than bytes requested by the
1998 * client. OS/2 servers are known to set incorrect
1999 * CountHigh values.
2000 */
2001 if (written > wdata->bytes)
2002 written &= 0xFFFF;
2003
2004 if (written < wdata->bytes)
2005 wdata->result = -ENOSPC;
2006 else
2007 wdata->bytes = written;
2008 break;
2009 case MID_REQUEST_SUBMITTED:
2010 case MID_RETRY_NEEDED:
2011 wdata->result = -EAGAIN;
2012 break;
2013 default:
2014 wdata->result = -EIO;
2015 break;
2016 }
2017
Jeff Laytonda472fc2012-03-23 14:40:53 -04002018 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002019 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002020 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002021}
2022
2023/* cifs_async_writev - send an async write, and set up mid to handle result */
2024int
Steve French4a5c80d2014-02-07 20:45:12 -06002025cifs_async_writev(struct cifs_writedata *wdata,
2026 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002027{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002028 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002029 WRITE_REQ *smb = NULL;
2030 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002031 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002032 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002033 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002034
2035 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2036 wct = 14;
2037 } else {
2038 wct = 12;
2039 if (wdata->offset >> 32 > 0) {
2040 /* can not handle big offset for old srv */
2041 return -EIO;
2042 }
2043 }
2044
2045 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2046 if (rc)
2047 goto async_writev_out;
2048
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002049 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2050 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002051
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002053 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002054 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2055 if (wct == 14)
2056 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2057 smb->Reserved = 0xFFFFFFFF;
2058 smb->WriteMode = 0;
2059 smb->Remaining = 0;
2060
2061 smb->DataOffset =
2062 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2063
2064 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002065 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2066 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002067
Jeff Laytoneddb0792012-09-18 16:20:35 -07002068 rqst.rq_iov = &iov;
2069 rqst.rq_nvec = 1;
2070 rqst.rq_pages = wdata->pages;
2071 rqst.rq_npages = wdata->nr_pages;
2072 rqst.rq_pagesz = wdata->pagesz;
2073 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002074
Joe Perchesf96637b2013-05-04 22:12:25 -05002075 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2076 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077
2078 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2079 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2080
2081 if (wct == 14) {
2082 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2083 put_bcc(wdata->bytes + 1, &smb->hdr);
2084 } else {
2085 /* wct == 12 */
2086 struct smb_com_writex_req *smbw =
2087 (struct smb_com_writex_req *)smb;
2088 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2089 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002090 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002091 }
2092
2093 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002094 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2095 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002096
2097 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002098 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099 else
Steve French4a5c80d2014-02-07 20:45:12 -06002100 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102async_writev_out:
2103 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002104 return rc;
2105}
2106
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002107int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002108CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002109 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110{
2111 int rc = -EACCES;
2112 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002113 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002114 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002115 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002116 __u32 pid = io_parms->pid;
2117 __u16 netfid = io_parms->netfid;
2118 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002119 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002120 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002122 *nbytes = 0;
2123
Joe Perchesf96637b2013-05-04 22:12:25 -05002124 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002125
Steve French4c3130e2008-12-09 00:28:16 +00002126 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002127 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002128 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002129 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002130 if ((offset >> 32) > 0) {
2131 /* can not handle big offset for old srv */
2132 return -EIO;
2133 }
2134 }
Steve French8cc64c62005-10-03 13:49:43 -07002135 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 if (rc)
2137 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002138
2139 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2140 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 /* tcon and ses pointer are checked in smb_init */
2143 if (tcon->ses->server == NULL)
2144 return -ECONNABORTED;
2145
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002146 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 pSMB->Fid = netfid;
2148 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002149 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002150 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 pSMB->Reserved = 0xFFFFFFFF;
2152 pSMB->WriteMode = 0;
2153 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002154
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002156 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Steve French3e844692005-10-03 13:37:24 -07002158 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2159 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002160 /* header + 1 byte pad */
2161 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002162 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002163 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002164 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002165 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002166 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002167 pSMB->ByteCount = cpu_to_le16(count + 1);
2168 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002169 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002170 (struct smb_com_writex_req *)pSMB;
2171 pSMBW->ByteCount = cpu_to_le16(count + 5);
2172 }
Steve French3e844692005-10-03 13:37:24 -07002173 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002174 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002175 iov[0].iov_len = smb_hdr_len + 4;
2176 else /* wct == 12 pad bigger by four bytes */
2177 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002178
Steve French3e844692005-10-03 13:37:24 -07002179
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002180 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002181 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002183 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002184 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002185 /* presumably this can not happen, but best to be safe */
2186 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002187 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002188 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002189 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2190 *nbytes = (*nbytes) << 16;
2191 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302192
2193 /*
2194 * Mask off high 16 bits when bytes written as returned by the
2195 * server is greater than bytes requested by the client. OS/2
2196 * servers are known to set incorrect CountHigh values.
2197 */
2198 if (*nbytes > count)
2199 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Steve French4b8f9302006-02-26 16:41:18 +00002202/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002203 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204
Steve French50c2f752007-07-13 00:33:32 +00002205 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 since file handle passed in no longer valid */
2207
2208 return rc;
2209}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002210
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002211int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2212 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002213 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2214{
2215 int rc = 0;
2216 LOCK_REQ *pSMB = NULL;
2217 struct kvec iov[2];
2218 int resp_buf_type;
2219 __u16 count;
2220
Joe Perchesf96637b2013-05-04 22:12:25 -05002221 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2222 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002223
2224 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2225 if (rc)
2226 return rc;
2227
2228 pSMB->Timeout = 0;
2229 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2230 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2231 pSMB->LockType = lock_type;
2232 pSMB->AndXCommand = 0xFF; /* none */
2233 pSMB->Fid = netfid; /* netfid stays le */
2234
2235 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2236 inc_rfc1001_len(pSMB, count);
2237 pSMB->ByteCount = cpu_to_le16(count);
2238
2239 iov[0].iov_base = (char *)pSMB;
2240 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2241 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2242 iov[1].iov_base = (char *)buf;
2243 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2244
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002245 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002246 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2247 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002248 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002249
2250 return rc;
2251}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002252
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002254CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002255 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002257 const __u32 numLock, const __u8 lockType,
2258 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259{
2260 int rc = 0;
2261 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002262/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002264 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 __u16 count;
2266
Joe Perchesf96637b2013-05-04 22:12:25 -05002267 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2268 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002269 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2270
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 if (rc)
2272 return rc;
2273
Steve French790fe572007-07-07 19:25:05 +00002274 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002275 /* no response expected */
2276 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002278 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002279 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2281 } else {
2282 pSMB->Timeout = 0;
2283 }
2284
2285 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2286 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2287 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002288 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 pSMB->AndXCommand = 0xFF; /* none */
2290 pSMB->Fid = smb_file_id; /* netfid stays le */
2291
Steve French790fe572007-07-07 19:25:05 +00002292 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002293 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 /* BB where to store pid high? */
2295 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2296 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2297 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2298 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2299 count = sizeof(LOCKING_ANDX_RANGE);
2300 } else {
2301 /* oplock break */
2302 count = 0;
2303 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002304 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 pSMB->ByteCount = cpu_to_le16(count);
2306
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002307 if (waitFlag) {
2308 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002309 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002310 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002311 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002312 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002313 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002314 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002315 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002316 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002317 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
Steve French50c2f752007-07-13 00:33:32 +00002319 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 since file handle passed in no longer valid */
2321 return rc;
2322}
2323
2324int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002325CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002326 const __u16 smb_file_id, const __u32 netpid,
2327 const loff_t start_offset, const __u64 len,
2328 struct file_lock *pLockData, const __u16 lock_type,
2329 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002330{
2331 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2332 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002333 struct cifs_posix_lock *parm_data;
2334 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002335 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002336 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002337 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002338 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002339 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002340
Joe Perchesf96637b2013-05-04 22:12:25 -05002341 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002342
Steve French08547b02006-02-28 22:39:25 +00002343 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2344
2345 if (rc)
2346 return rc;
2347
2348 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2349
Steve French50c2f752007-07-13 00:33:32 +00002350 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002351 pSMB->MaxSetupCount = 0;
2352 pSMB->Reserved = 0;
2353 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002354 pSMB->Reserved2 = 0;
2355 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2356 offset = param_offset + params;
2357
Steve French08547b02006-02-28 22:39:25 +00002358 count = sizeof(struct cifs_posix_lock);
2359 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002360 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002361 pSMB->SetupCount = 1;
2362 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002363 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002364 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2365 else
2366 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2367 byte_count = 3 /* pad */ + params + count;
2368 pSMB->DataCount = cpu_to_le16(count);
2369 pSMB->ParameterCount = cpu_to_le16(params);
2370 pSMB->TotalDataCount = pSMB->DataCount;
2371 pSMB->TotalParameterCount = pSMB->ParameterCount;
2372 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002373 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002374 (((char *) &pSMB->hdr.Protocol) + offset);
2375
2376 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002377 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002378 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002379 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002380 pSMB->Timeout = cpu_to_le32(-1);
2381 } else
2382 pSMB->Timeout = 0;
2383
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002384 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002385 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002386 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002387
2388 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002389 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002390 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2391 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002392 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002393 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002394 if (waitFlag) {
2395 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2396 (struct smb_hdr *) pSMBr, &bytes_returned);
2397 } else {
Steve French133672e2007-11-13 22:41:37 +00002398 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002399 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002400 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2401 &resp_buf_type, timeout);
2402 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2403 not try to free it twice below on exit */
2404 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002405 }
2406
Steve French08547b02006-02-28 22:39:25 +00002407 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002408 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002409 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002410 /* lock structure can be returned on get */
2411 __u16 data_offset;
2412 __u16 data_count;
2413 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002414
Jeff Layton820a8032011-05-04 08:05:26 -04002415 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002416 rc = -EIO; /* bad smb */
2417 goto plk_err_exit;
2418 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002419 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2420 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002421 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002422 rc = -EIO;
2423 goto plk_err_exit;
2424 }
2425 parm_data = (struct cifs_posix_lock *)
2426 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002427 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002428 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002429 else {
2430 if (parm_data->lock_type ==
2431 __constant_cpu_to_le16(CIFS_RDLCK))
2432 pLockData->fl_type = F_RDLCK;
2433 else if (parm_data->lock_type ==
2434 __constant_cpu_to_le16(CIFS_WRLCK))
2435 pLockData->fl_type = F_WRLCK;
2436
Steve French5443d132011-03-13 05:08:25 +00002437 pLockData->fl_start = le64_to_cpu(parm_data->start);
2438 pLockData->fl_end = pLockData->fl_start +
2439 le64_to_cpu(parm_data->length) - 1;
2440 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002441 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002442 }
Steve French50c2f752007-07-13 00:33:32 +00002443
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002444plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002445 if (pSMB)
2446 cifs_small_buf_release(pSMB);
2447
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01002448 free_rsp_buf(resp_buf_type, iov[0].iov_base);
Steve French133672e2007-11-13 22:41:37 +00002449
Steve French08547b02006-02-28 22:39:25 +00002450 /* Note: On -EAGAIN error only caller can retry on handle based calls
2451 since file handle passed in no longer valid */
2452
2453 return rc;
2454}
2455
2456
2457int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002458CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
2460 int rc = 0;
2461 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002462 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
2464/* do not retry on dead session on close */
2465 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002466 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 return 0;
2468 if (rc)
2469 return rc;
2470
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002472 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002474 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002475 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002477 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002479 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 }
2481 }
2482
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002484 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 rc = 0;
2486
2487 return rc;
2488}
2489
2490int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002491CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002492{
2493 int rc = 0;
2494 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002495 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002496
2497 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2498 if (rc)
2499 return rc;
2500
2501 pSMB->FileID = (__u16) smb_file_id;
2502 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002503 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002504 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002505 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002506 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002507
2508 return rc;
2509}
2510
2511int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002512CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002513 const char *from_name, const char *to_name,
2514 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515{
2516 int rc = 0;
2517 RENAME_REQ *pSMB = NULL;
2518 RENAME_RSP *pSMBr = NULL;
2519 int bytes_returned;
2520 int name_len, name_len2;
2521 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002522 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
Joe Perchesf96637b2013-05-04 22:12:25 -05002524 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525renameRetry:
2526 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2527 (void **) &pSMBr);
2528 if (rc)
2529 return rc;
2530
2531 pSMB->BufferFormat = 0x04;
2532 pSMB->SearchAttributes =
2533 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2534 ATTR_DIRECTORY);
2535
2536 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002537 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2538 from_name, PATH_MAX,
2539 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 name_len++; /* trailing null */
2541 name_len *= 2;
2542 pSMB->OldFileName[name_len] = 0x04; /* pad */
2543 /* protocol requires ASCII signature byte on Unicode string */
2544 pSMB->OldFileName[name_len + 1] = 0x00;
2545 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002546 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002547 to_name, PATH_MAX, cifs_sb->local_nls,
2548 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2550 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002551 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002552 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002554 strncpy(pSMB->OldFileName, from_name, name_len);
2555 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 name_len2++; /* trailing null */
2557 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002558 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 name_len2++; /* trailing null */
2560 name_len2++; /* signature byte */
2561 }
2562
2563 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002564 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 pSMB->ByteCount = cpu_to_le16(count);
2566
2567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002569 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002570 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002571 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 cifs_buf_release(pSMB);
2574
2575 if (rc == -EAGAIN)
2576 goto renameRetry;
2577
2578 return rc;
2579}
2580
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002581int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002582 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002583 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584{
2585 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2586 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002587 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 char *data_offset;
2589 char dummy_string[30];
2590 int rc = 0;
2591 int bytes_returned = 0;
2592 int len_of_str;
2593 __u16 params, param_offset, offset, count, byte_count;
2594
Joe Perchesf96637b2013-05-04 22:12:25 -05002595 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2597 (void **) &pSMBr);
2598 if (rc)
2599 return rc;
2600
2601 params = 6;
2602 pSMB->MaxSetupCount = 0;
2603 pSMB->Reserved = 0;
2604 pSMB->Flags = 0;
2605 pSMB->Timeout = 0;
2606 pSMB->Reserved2 = 0;
2607 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2608 offset = param_offset + params;
2609
2610 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2611 rename_info = (struct set_file_rename *) data_offset;
2612 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002613 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 pSMB->SetupCount = 1;
2615 pSMB->Reserved3 = 0;
2616 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2617 byte_count = 3 /* pad */ + params;
2618 pSMB->ParameterCount = cpu_to_le16(params);
2619 pSMB->TotalParameterCount = pSMB->ParameterCount;
2620 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2621 pSMB->DataOffset = cpu_to_le16(offset);
2622 /* construct random name ".cifs_tmp<inodenum><mid>" */
2623 rename_info->overwrite = cpu_to_le32(1);
2624 rename_info->root_fid = 0;
2625 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002626 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002627 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002628 len_of_str =
2629 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002630 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002632 len_of_str =
2633 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002634 target_name, PATH_MAX, nls_codepage,
2635 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 }
2637 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002638 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 byte_count += count;
2640 pSMB->DataCount = cpu_to_le16(count);
2641 pSMB->TotalDataCount = pSMB->DataCount;
2642 pSMB->Fid = netfid;
2643 pSMB->InformationLevel =
2644 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2645 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002646 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 pSMB->ByteCount = cpu_to_le16(byte_count);
2648 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002649 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002650 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002651 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002652 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2653 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002654
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 cifs_buf_release(pSMB);
2656
2657 /* Note: On -EAGAIN error only caller can retry on handle based calls
2658 since file handle passed in no longer valid */
2659
2660 return rc;
2661}
2662
2663int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002664CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2665 const char *fromName, const __u16 target_tid, const char *toName,
2666 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667{
2668 int rc = 0;
2669 COPY_REQ *pSMB = NULL;
2670 COPY_RSP *pSMBr = NULL;
2671 int bytes_returned;
2672 int name_len, name_len2;
2673 __u16 count;
2674
Joe Perchesf96637b2013-05-04 22:12:25 -05002675 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676copyRetry:
2677 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2678 (void **) &pSMBr);
2679 if (rc)
2680 return rc;
2681
2682 pSMB->BufferFormat = 0x04;
2683 pSMB->Tid2 = target_tid;
2684
2685 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2686
2687 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002688 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2689 fromName, PATH_MAX, nls_codepage,
2690 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 name_len++; /* trailing null */
2692 name_len *= 2;
2693 pSMB->OldFileName[name_len] = 0x04; /* pad */
2694 /* protocol requires ASCII signature byte on Unicode string */
2695 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002696 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002697 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2698 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2700 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002701 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 name_len = strnlen(fromName, PATH_MAX);
2703 name_len++; /* trailing null */
2704 strncpy(pSMB->OldFileName, fromName, name_len);
2705 name_len2 = strnlen(toName, PATH_MAX);
2706 name_len2++; /* trailing null */
2707 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2708 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2709 name_len2++; /* trailing null */
2710 name_len2++; /* signature byte */
2711 }
2712
2713 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002714 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 pSMB->ByteCount = cpu_to_le16(count);
2716
2717 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2718 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2719 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002720 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2721 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 }
Steve French0d817bc2008-05-22 02:02:03 +00002723 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
2725 if (rc == -EAGAIN)
2726 goto copyRetry;
2727
2728 return rc;
2729}
2730
2731int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002732CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 const char *fromName, const char *toName,
2734 const struct nls_table *nls_codepage)
2735{
2736 TRANSACTION2_SPI_REQ *pSMB = NULL;
2737 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2738 char *data_offset;
2739 int name_len;
2740 int name_len_target;
2741 int rc = 0;
2742 int bytes_returned = 0;
2743 __u16 params, param_offset, offset, byte_count;
2744
Joe Perchesf96637b2013-05-04 22:12:25 -05002745 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746createSymLinkRetry:
2747 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2748 (void **) &pSMBr);
2749 if (rc)
2750 return rc;
2751
2752 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2753 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002754 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2755 /* find define for this maxpathcomponent */
2756 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 name_len++; /* trailing null */
2758 name_len *= 2;
2759
Steve French50c2f752007-07-13 00:33:32 +00002760 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 name_len = strnlen(fromName, PATH_MAX);
2762 name_len++; /* trailing null */
2763 strncpy(pSMB->FileName, fromName, name_len);
2764 }
2765 params = 6 + name_len;
2766 pSMB->MaxSetupCount = 0;
2767 pSMB->Reserved = 0;
2768 pSMB->Flags = 0;
2769 pSMB->Timeout = 0;
2770 pSMB->Reserved2 = 0;
2771 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002772 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 offset = param_offset + params;
2774
2775 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2776 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2777 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002778 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2779 /* find define for this maxpathcomponent */
2780 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 name_len_target++; /* trailing null */
2782 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002783 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 name_len_target = strnlen(toName, PATH_MAX);
2785 name_len_target++; /* trailing null */
2786 strncpy(data_offset, toName, name_len_target);
2787 }
2788
2789 pSMB->MaxParameterCount = cpu_to_le16(2);
2790 /* BB find exact max on data count below from sess */
2791 pSMB->MaxDataCount = cpu_to_le16(1000);
2792 pSMB->SetupCount = 1;
2793 pSMB->Reserved3 = 0;
2794 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2795 byte_count = 3 /* pad */ + params + name_len_target;
2796 pSMB->DataCount = cpu_to_le16(name_len_target);
2797 pSMB->ParameterCount = cpu_to_le16(params);
2798 pSMB->TotalDataCount = pSMB->DataCount;
2799 pSMB->TotalParameterCount = pSMB->ParameterCount;
2800 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2801 pSMB->DataOffset = cpu_to_le16(offset);
2802 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2803 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002804 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 pSMB->ByteCount = cpu_to_le16(byte_count);
2806 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2807 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002808 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002809 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002810 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2811 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
Steve French0d817bc2008-05-22 02:02:03 +00002813 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
2815 if (rc == -EAGAIN)
2816 goto createSymLinkRetry;
2817
2818 return rc;
2819}
2820
2821int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002822CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002824 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825{
2826 TRANSACTION2_SPI_REQ *pSMB = NULL;
2827 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2828 char *data_offset;
2829 int name_len;
2830 int name_len_target;
2831 int rc = 0;
2832 int bytes_returned = 0;
2833 __u16 params, param_offset, offset, byte_count;
2834
Joe Perchesf96637b2013-05-04 22:12:25 -05002835 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836createHardLinkRetry:
2837 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2838 (void **) &pSMBr);
2839 if (rc)
2840 return rc;
2841
2842 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002843 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2844 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 name_len++; /* trailing null */
2846 name_len *= 2;
2847
Steve French50c2f752007-07-13 00:33:32 +00002848 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 name_len = strnlen(toName, PATH_MAX);
2850 name_len++; /* trailing null */
2851 strncpy(pSMB->FileName, toName, name_len);
2852 }
2853 params = 6 + name_len;
2854 pSMB->MaxSetupCount = 0;
2855 pSMB->Reserved = 0;
2856 pSMB->Flags = 0;
2857 pSMB->Timeout = 0;
2858 pSMB->Reserved2 = 0;
2859 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002860 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 offset = param_offset + params;
2862
2863 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2865 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002866 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2867 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 name_len_target++; /* trailing null */
2869 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002870 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 name_len_target = strnlen(fromName, PATH_MAX);
2872 name_len_target++; /* trailing null */
2873 strncpy(data_offset, fromName, name_len_target);
2874 }
2875
2876 pSMB->MaxParameterCount = cpu_to_le16(2);
2877 /* BB find exact max on data count below from sess*/
2878 pSMB->MaxDataCount = cpu_to_le16(1000);
2879 pSMB->SetupCount = 1;
2880 pSMB->Reserved3 = 0;
2881 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2882 byte_count = 3 /* pad */ + params + name_len_target;
2883 pSMB->ParameterCount = cpu_to_le16(params);
2884 pSMB->TotalParameterCount = pSMB->ParameterCount;
2885 pSMB->DataCount = cpu_to_le16(name_len_target);
2886 pSMB->TotalDataCount = pSMB->DataCount;
2887 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2888 pSMB->DataOffset = cpu_to_le16(offset);
2889 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2890 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002891 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 pSMB->ByteCount = cpu_to_le16(byte_count);
2893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002895 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002896 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002897 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2898 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899
2900 cifs_buf_release(pSMB);
2901 if (rc == -EAGAIN)
2902 goto createHardLinkRetry;
2903
2904 return rc;
2905}
2906
2907int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002908CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002909 const char *from_name, const char *to_name,
2910 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911{
2912 int rc = 0;
2913 NT_RENAME_REQ *pSMB = NULL;
2914 RENAME_RSP *pSMBr = NULL;
2915 int bytes_returned;
2916 int name_len, name_len2;
2917 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002918 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
Joe Perchesf96637b2013-05-04 22:12:25 -05002920 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921winCreateHardLinkRetry:
2922
2923 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2924 (void **) &pSMBr);
2925 if (rc)
2926 return rc;
2927
2928 pSMB->SearchAttributes =
2929 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2930 ATTR_DIRECTORY);
2931 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2932 pSMB->ClusterCount = 0;
2933
2934 pSMB->BufferFormat = 0x04;
2935
2936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2937 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002938 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2939 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 name_len++; /* trailing null */
2941 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002942
2943 /* protocol specifies ASCII buffer format (0x04) for unicode */
2944 pSMB->OldFileName[name_len] = 0x04;
2945 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002947 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002948 to_name, PATH_MAX, cifs_sb->local_nls,
2949 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2951 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002952 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002953 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002955 strncpy(pSMB->OldFileName, from_name, name_len);
2956 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 name_len2++; /* trailing null */
2958 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002959 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len2++; /* trailing null */
2961 name_len2++; /* signature byte */
2962 }
2963
2964 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002965 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 pSMB->ByteCount = cpu_to_le16(count);
2967
2968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002970 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002971 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002972 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002973
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 cifs_buf_release(pSMB);
2975 if (rc == -EAGAIN)
2976 goto winCreateHardLinkRetry;
2977
2978 return rc;
2979}
2980
2981int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002982CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002983 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 const struct nls_table *nls_codepage)
2985{
2986/* SMB_QUERY_FILE_UNIX_LINK */
2987 TRANSACTION2_QPI_REQ *pSMB = NULL;
2988 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2989 int rc = 0;
2990 int bytes_returned;
2991 int name_len;
2992 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002993 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
Joe Perchesf96637b2013-05-04 22:12:25 -05002995 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996
2997querySymLinkRetry:
2998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999 (void **) &pSMBr);
3000 if (rc)
3001 return rc;
3002
3003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3004 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003005 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3006 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 name_len++; /* trailing null */
3008 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003009 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 name_len = strnlen(searchName, PATH_MAX);
3011 name_len++; /* trailing null */
3012 strncpy(pSMB->FileName, searchName, name_len);
3013 }
3014
3015 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3016 pSMB->TotalDataCount = 0;
3017 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003018 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 pSMB->MaxSetupCount = 0;
3020 pSMB->Reserved = 0;
3021 pSMB->Flags = 0;
3022 pSMB->Timeout = 0;
3023 pSMB->Reserved2 = 0;
3024 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003025 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 pSMB->DataCount = 0;
3027 pSMB->DataOffset = 0;
3028 pSMB->SetupCount = 1;
3029 pSMB->Reserved3 = 0;
3030 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3031 byte_count = params + 1 /* pad */ ;
3032 pSMB->TotalParameterCount = cpu_to_le16(params);
3033 pSMB->ParameterCount = pSMB->TotalParameterCount;
3034 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3035 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003036 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 pSMB->ByteCount = cpu_to_le16(byte_count);
3038
3039 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3040 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3041 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003042 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 } else {
3044 /* decode response */
3045
3046 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003048 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003049 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003051 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003052 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053
Jeff Layton460b9692009-04-30 07:17:56 -04003054 data_start = ((char *) &pSMBr->hdr.Protocol) +
3055 le16_to_cpu(pSMBr->t2.DataOffset);
3056
Steve French0e0d2cf2009-05-01 05:27:32 +00003057 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3058 is_unicode = true;
3059 else
3060 is_unicode = false;
3061
Steve French737b7582005-04-28 22:41:06 -07003062 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003063 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3064 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003065 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003066 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 }
3068 }
3069 cifs_buf_release(pSMB);
3070 if (rc == -EAGAIN)
3071 goto querySymLinkRetry;
3072 return rc;
3073}
3074
Steve Frenchc52a9552011-02-24 06:16:22 +00003075/*
3076 * Recent Windows versions now create symlinks more frequently
3077 * and they use the "reparse point" mechanism below. We can of course
3078 * do symlinks nicely to Samba and other servers which support the
3079 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3080 * "MF" symlinks optionally, but for recent Windows we really need to
3081 * reenable the code below and fix the cifs_symlink callers to handle this.
3082 * In the interim this code has been moved to its own config option so
3083 * it is not compiled in by default until callers fixed up and more tested.
3084 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003086CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3087 __u16 fid, char **symlinkinfo,
3088 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089{
3090 int rc = 0;
3091 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003092 struct smb_com_transaction_ioctl_req *pSMB;
3093 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003094 bool is_unicode;
3095 unsigned int sub_len;
3096 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003097 struct reparse_symlink_data *reparse_buf;
3098 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003099 __u32 data_offset, data_count;
3100 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003102 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3104 (void **) &pSMBr);
3105 if (rc)
3106 return rc;
3107
3108 pSMB->TotalParameterCount = 0 ;
3109 pSMB->TotalDataCount = 0;
3110 pSMB->MaxParameterCount = cpu_to_le32(2);
3111 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003112 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 pSMB->MaxSetupCount = 4;
3114 pSMB->Reserved = 0;
3115 pSMB->ParameterOffset = 0;
3116 pSMB->DataCount = 0;
3117 pSMB->DataOffset = 0;
3118 pSMB->SetupCount = 4;
3119 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3120 pSMB->ParameterCount = pSMB->TotalParameterCount;
3121 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3122 pSMB->IsFsctl = 1; /* FSCTL */
3123 pSMB->IsRootFlag = 0;
3124 pSMB->Fid = fid; /* file handle always le */
3125 pSMB->ByteCount = 0;
3126
3127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3129 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003130 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003131 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 }
Steve French989c7e52009-05-02 05:32:20 +00003133
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003134 data_offset = le32_to_cpu(pSMBr->DataOffset);
3135 data_count = le32_to_cpu(pSMBr->DataCount);
3136 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3137 /* BB also check enough total bytes returned */
3138 rc = -EIO; /* bad smb */
3139 goto qreparse_out;
3140 }
3141 if (!data_count || (data_count > 2048)) {
3142 rc = -EIO;
3143 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3144 goto qreparse_out;
3145 }
3146 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003147 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003148 ((char *)&pSMBr->hdr.Protocol + data_offset);
3149 if ((char *)reparse_buf >= end_of_smb) {
3150 rc = -EIO;
3151 goto qreparse_out;
3152 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003153 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3154 cifs_dbg(FYI, "NFS style reparse tag\n");
3155 posix_buf = (struct reparse_posix_data *)reparse_buf;
3156
3157 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3158 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3159 le64_to_cpu(posix_buf->InodeType));
3160 rc = -EOPNOTSUPP;
3161 goto qreparse_out;
3162 }
3163 is_unicode = true;
3164 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3165 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3166 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3167 rc = -EIO;
3168 goto qreparse_out;
3169 }
3170 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3171 sub_len, is_unicode, nls_codepage);
3172 goto qreparse_out;
3173 } else if (reparse_buf->ReparseTag !=
3174 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3175 rc = -EOPNOTSUPP;
3176 goto qreparse_out;
3177 }
3178
3179 /* Reparse tag is NTFS symlink */
3180 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3181 reparse_buf->PathBuffer;
3182 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3183 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003184 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3185 rc = -EIO;
3186 goto qreparse_out;
3187 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003188 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3189 is_unicode = true;
3190 else
3191 is_unicode = false;
3192
3193 /* BB FIXME investigate remapping reserved chars here */
3194 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3195 nls_codepage);
3196 if (!*symlinkinfo)
3197 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003199 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003201 /*
3202 * Note: On -EAGAIN error only caller can retry on handle based calls
3203 * since file handle passed in no longer valid.
3204 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 return rc;
3206}
3207
Steve Frenchc7f508a2013-10-14 15:27:32 -05003208int
3209CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3210 __u16 fid)
3211{
3212 int rc = 0;
3213 int bytes_returned;
3214 struct smb_com_transaction_compr_ioctl_req *pSMB;
3215 struct smb_com_transaction_ioctl_rsp *pSMBr;
3216
3217 cifs_dbg(FYI, "Set compression for %u\n", fid);
3218 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3219 (void **) &pSMBr);
3220 if (rc)
3221 return rc;
3222
3223 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3224
3225 pSMB->TotalParameterCount = 0;
3226 pSMB->TotalDataCount = __constant_cpu_to_le32(2);
3227 pSMB->MaxParameterCount = 0;
3228 pSMB->MaxDataCount = 0;
3229 pSMB->MaxSetupCount = 4;
3230 pSMB->Reserved = 0;
3231 pSMB->ParameterOffset = 0;
3232 pSMB->DataCount = __constant_cpu_to_le32(2);
3233 pSMB->DataOffset =
3234 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3235 compression_state) - 4); /* 84 */
3236 pSMB->SetupCount = 4;
3237 pSMB->SubCommand = __constant_cpu_to_le16(NT_TRANSACT_IOCTL);
3238 pSMB->ParameterCount = 0;
3239 pSMB->FunctionCode = __constant_cpu_to_le32(FSCTL_SET_COMPRESSION);
3240 pSMB->IsFsctl = 1; /* FSCTL */
3241 pSMB->IsRootFlag = 0;
3242 pSMB->Fid = fid; /* file handle always le */
3243 /* 3 byte pad, followed by 2 byte compress state */
3244 pSMB->ByteCount = __constant_cpu_to_le16(5);
3245 inc_rfc1001_len(pSMB, 5);
3246
3247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3248 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3249 if (rc)
3250 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3251
3252 cifs_buf_release(pSMB);
3253
3254 /*
3255 * Note: On -EAGAIN error only caller can retry on handle based calls
3256 * since file handle passed in no longer valid.
3257 */
3258 return rc;
3259}
3260
3261
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262#ifdef CONFIG_CIFS_POSIX
3263
3264/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003265static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3266 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267{
3268 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003269 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3270 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3271 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003272/*
3273 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3274 ace->e_perm, ace->e_tag, ace->e_id);
3275*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
3277 return;
3278}
3279
3280/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003281static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3282 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283{
3284 int size = 0;
3285 int i;
3286 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003287 struct cifs_posix_ace *pACE;
3288 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3289 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
3291 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3292 return -EOPNOTSUPP;
3293
Steve French790fe572007-07-07 19:25:05 +00003294 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 count = le16_to_cpu(cifs_acl->access_entry_count);
3296 pACE = &cifs_acl->ace_array[0];
3297 size = sizeof(struct cifs_posix_acl);
3298 size += sizeof(struct cifs_posix_ace) * count;
3299 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003300 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003301 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3302 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 return -EINVAL;
3304 }
Steve French790fe572007-07-07 19:25:05 +00003305 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 count = le16_to_cpu(cifs_acl->access_entry_count);
3307 size = sizeof(struct cifs_posix_acl);
3308 size += sizeof(struct cifs_posix_ace) * count;
3309/* skip past access ACEs to get to default ACEs */
3310 pACE = &cifs_acl->ace_array[count];
3311 count = le16_to_cpu(cifs_acl->default_entry_count);
3312 size += sizeof(struct cifs_posix_ace) * count;
3313 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003314 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 return -EINVAL;
3316 } else {
3317 /* illegal type */
3318 return -EINVAL;
3319 }
3320
3321 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003322 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003323 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003324 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 return -ERANGE;
3326 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003327 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003328 for (i = 0; i < count ; i++) {
3329 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3330 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 }
3332 }
3333 return size;
3334}
3335
Steve French50c2f752007-07-13 00:33:32 +00003336static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3337 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338{
3339 __u16 rc = 0; /* 0 = ACL converted ok */
3340
Steve Frenchff7feac2005-11-15 16:45:16 -08003341 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3342 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003344 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 /* Probably no need to le convert -1 on any arch but can not hurt */
3346 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003347 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003348 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003349/*
3350 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3351 ace->e_perm, ace->e_tag, ace->e_id);
3352*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 return rc;
3354}
3355
3356/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003357static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3358 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359{
3360 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003361 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3362 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 int count;
3364 int i;
3365
Steve French790fe572007-07-07 19:25:05 +00003366 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 return 0;
3368
3369 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003370 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3371 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003372 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003373 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3374 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 return 0;
3376 }
3377 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003378 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003379 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve Frenchb1d93352013-11-15 20:41:32 -06003380 cifs_acl->default_entry_count = __constant_cpu_to_le16(0xFFFF);
3381 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003382 cifs_acl->default_entry_count = cpu_to_le16(count);
Steve Frenchb1d93352013-11-15 20:41:32 -06003383 cifs_acl->access_entry_count = __constant_cpu_to_le16(0xFFFF);
3384 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003385 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 return 0;
3387 }
Steve French50c2f752007-07-13 00:33:32 +00003388 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3390 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003391 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 /* ACE not converted */
3393 break;
3394 }
3395 }
Steve French790fe572007-07-07 19:25:05 +00003396 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3398 rc += sizeof(struct cifs_posix_acl);
3399 /* BB add check to make sure ACL does not overflow SMB */
3400 }
3401 return rc;
3402}
3403
3404int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003405CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003406 const unsigned char *searchName,
3407 char *acl_inf, const int buflen, const int acl_type,
3408 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409{
3410/* SMB_QUERY_POSIX_ACL */
3411 TRANSACTION2_QPI_REQ *pSMB = NULL;
3412 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3413 int rc = 0;
3414 int bytes_returned;
3415 int name_len;
3416 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003417
Joe Perchesf96637b2013-05-04 22:12:25 -05003418 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419
3420queryAclRetry:
3421 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3422 (void **) &pSMBr);
3423 if (rc)
3424 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003425
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3427 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003428 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3429 searchName, PATH_MAX, nls_codepage,
3430 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 name_len++; /* trailing null */
3432 name_len *= 2;
3433 pSMB->FileName[name_len] = 0;
3434 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003435 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 name_len = strnlen(searchName, PATH_MAX);
3437 name_len++; /* trailing null */
3438 strncpy(pSMB->FileName, searchName, name_len);
3439 }
3440
3441 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3442 pSMB->TotalDataCount = 0;
3443 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003444 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 pSMB->MaxDataCount = cpu_to_le16(4000);
3446 pSMB->MaxSetupCount = 0;
3447 pSMB->Reserved = 0;
3448 pSMB->Flags = 0;
3449 pSMB->Timeout = 0;
3450 pSMB->Reserved2 = 0;
3451 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003452 offsetof(struct smb_com_transaction2_qpi_req,
3453 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 pSMB->DataCount = 0;
3455 pSMB->DataOffset = 0;
3456 pSMB->SetupCount = 1;
3457 pSMB->Reserved3 = 0;
3458 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3459 byte_count = params + 1 /* pad */ ;
3460 pSMB->TotalParameterCount = cpu_to_le16(params);
3461 pSMB->ParameterCount = pSMB->TotalParameterCount;
3462 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3463 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003464 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 pSMB->ByteCount = cpu_to_le16(byte_count);
3466
3467 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3468 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003469 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003471 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 } else {
3473 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003474
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003477 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 rc = -EIO; /* bad smb */
3479 else {
3480 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3481 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3482 rc = cifs_copy_posix_acl(acl_inf,
3483 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003484 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 }
3486 }
3487 cifs_buf_release(pSMB);
3488 if (rc == -EAGAIN)
3489 goto queryAclRetry;
3490 return rc;
3491}
3492
3493int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003494CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003495 const unsigned char *fileName,
3496 const char *local_acl, const int buflen,
3497 const int acl_type,
3498 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499{
3500 struct smb_com_transaction2_spi_req *pSMB = NULL;
3501 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3502 char *parm_data;
3503 int name_len;
3504 int rc = 0;
3505 int bytes_returned = 0;
3506 __u16 params, byte_count, data_count, param_offset, offset;
3507
Joe Perchesf96637b2013-05-04 22:12:25 -05003508 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509setAclRetry:
3510 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003511 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 if (rc)
3513 return rc;
3514 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3515 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003516 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3517 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 name_len++; /* trailing null */
3519 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003520 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 name_len = strnlen(fileName, PATH_MAX);
3522 name_len++; /* trailing null */
3523 strncpy(pSMB->FileName, fileName, name_len);
3524 }
3525 params = 6 + name_len;
3526 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003527 /* BB find max SMB size from sess */
3528 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 pSMB->MaxSetupCount = 0;
3530 pSMB->Reserved = 0;
3531 pSMB->Flags = 0;
3532 pSMB->Timeout = 0;
3533 pSMB->Reserved2 = 0;
3534 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003535 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 offset = param_offset + params;
3537 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3538 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3539
3540 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003541 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
Steve French790fe572007-07-07 19:25:05 +00003543 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 rc = -EOPNOTSUPP;
3545 goto setACLerrorExit;
3546 }
3547 pSMB->DataOffset = cpu_to_le16(offset);
3548 pSMB->SetupCount = 1;
3549 pSMB->Reserved3 = 0;
3550 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3551 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3552 byte_count = 3 /* pad */ + params + data_count;
3553 pSMB->DataCount = cpu_to_le16(data_count);
3554 pSMB->TotalDataCount = pSMB->DataCount;
3555 pSMB->ParameterCount = cpu_to_le16(params);
3556 pSMB->TotalParameterCount = pSMB->ParameterCount;
3557 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003558 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 pSMB->ByteCount = cpu_to_le16(byte_count);
3560 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003561 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003562 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003563 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
3565setACLerrorExit:
3566 cifs_buf_release(pSMB);
3567 if (rc == -EAGAIN)
3568 goto setAclRetry;
3569 return rc;
3570}
3571
Steve Frenchf654bac2005-04-28 22:41:04 -07003572/* BB fix tabs in this function FIXME BB */
3573int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003574CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003575 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003576{
Steve French50c2f752007-07-13 00:33:32 +00003577 int rc = 0;
3578 struct smb_t2_qfi_req *pSMB = NULL;
3579 struct smb_t2_qfi_rsp *pSMBr = NULL;
3580 int bytes_returned;
3581 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003582
Joe Perchesf96637b2013-05-04 22:12:25 -05003583 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003584 if (tcon == NULL)
3585 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003586
3587GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003588 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3589 (void **) &pSMBr);
3590 if (rc)
3591 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003592
Steve Frenchad7a2922008-02-07 23:25:02 +00003593 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003594 pSMB->t2.TotalDataCount = 0;
3595 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3596 /* BB find exact max data count below from sess structure BB */
3597 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3598 pSMB->t2.MaxSetupCount = 0;
3599 pSMB->t2.Reserved = 0;
3600 pSMB->t2.Flags = 0;
3601 pSMB->t2.Timeout = 0;
3602 pSMB->t2.Reserved2 = 0;
3603 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3604 Fid) - 4);
3605 pSMB->t2.DataCount = 0;
3606 pSMB->t2.DataOffset = 0;
3607 pSMB->t2.SetupCount = 1;
3608 pSMB->t2.Reserved3 = 0;
3609 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3610 byte_count = params + 1 /* pad */ ;
3611 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3612 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3613 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3614 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003615 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003616 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003617 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003618
Steve French790fe572007-07-07 19:25:05 +00003619 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3620 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3621 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003622 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003623 } else {
3624 /* decode response */
3625 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003626 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003627 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003628 /* If rc should we check for EOPNOSUPP and
3629 disable the srvino flag? or in caller? */
3630 rc = -EIO; /* bad smb */
3631 else {
3632 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3633 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3634 struct file_chattr_info *pfinfo;
3635 /* BB Do we need a cast or hash here ? */
3636 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003637 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003638 rc = -EIO;
3639 goto GetExtAttrOut;
3640 }
3641 pfinfo = (struct file_chattr_info *)
3642 (data_offset + (char *) &pSMBr->hdr.Protocol);
3643 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003644 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003645 }
3646 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003647GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003648 cifs_buf_release(pSMB);
3649 if (rc == -EAGAIN)
3650 goto GetExtAttrRetry;
3651 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003652}
3653
Steve Frenchf654bac2005-04-28 22:41:04 -07003654#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655
Jeff Layton79df1ba2010-12-06 12:52:08 -05003656#ifdef CONFIG_CIFS_ACL
3657/*
3658 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3659 * all NT TRANSACTS that we init here have total parm and data under about 400
3660 * bytes (to fit in small cifs buffer size), which is the case so far, it
3661 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3662 * returned setup area) and MaxParameterCount (returned parms size) must be set
3663 * by caller
3664 */
3665static int
3666smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003667 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003668 void **ret_buf)
3669{
3670 int rc;
3671 __u32 temp_offset;
3672 struct smb_com_ntransact_req *pSMB;
3673
3674 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3675 (void **)&pSMB);
3676 if (rc)
3677 return rc;
3678 *ret_buf = (void *)pSMB;
3679 pSMB->Reserved = 0;
3680 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3681 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003682 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003683 pSMB->ParameterCount = pSMB->TotalParameterCount;
3684 pSMB->DataCount = pSMB->TotalDataCount;
3685 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3686 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3687 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3688 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3689 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3690 pSMB->SubCommand = cpu_to_le16(sub_command);
3691 return 0;
3692}
3693
3694static int
3695validate_ntransact(char *buf, char **ppparm, char **ppdata,
3696 __u32 *pparmlen, __u32 *pdatalen)
3697{
3698 char *end_of_smb;
3699 __u32 data_count, data_offset, parm_count, parm_offset;
3700 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003701 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003702
3703 *pdatalen = 0;
3704 *pparmlen = 0;
3705
3706 if (buf == NULL)
3707 return -EINVAL;
3708
3709 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3710
Jeff Layton820a8032011-05-04 08:05:26 -04003711 bcc = get_bcc(&pSMBr->hdr);
3712 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003713 (char *)&pSMBr->ByteCount;
3714
3715 data_offset = le32_to_cpu(pSMBr->DataOffset);
3716 data_count = le32_to_cpu(pSMBr->DataCount);
3717 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3718 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3719
3720 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3721 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3722
3723 /* should we also check that parm and data areas do not overlap? */
3724 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003725 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003726 return -EINVAL;
3727 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003728 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003729 return -EINVAL;
3730 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003731 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003732 return -EINVAL;
3733 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003734 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3735 *ppdata, data_count, (data_count + *ppdata),
3736 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003737 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003738 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003739 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003740 return -EINVAL;
3741 }
3742 *pdatalen = data_count;
3743 *pparmlen = parm_count;
3744 return 0;
3745}
3746
Steve French0a4b92c2006-01-12 15:44:21 -08003747/* Get Security Descriptor (by handle) from remote server for a file or dir */
3748int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003749CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003750 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003751{
3752 int rc = 0;
3753 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003754 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003755 struct kvec iov[1];
3756
Joe Perchesf96637b2013-05-04 22:12:25 -05003757 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003758
Steve French630f3f0c2007-10-25 21:17:17 +00003759 *pbuflen = 0;
3760 *acl_inf = NULL;
3761
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003762 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003763 8 /* parm len */, tcon, (void **) &pSMB);
3764 if (rc)
3765 return rc;
3766
3767 pSMB->MaxParameterCount = cpu_to_le32(4);
3768 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3769 pSMB->MaxSetupCount = 0;
3770 pSMB->Fid = fid; /* file handle always le */
3771 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3772 CIFS_ACL_DACL);
3773 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003774 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003775 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003776 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003777
Steve Frencha761ac52007-10-18 21:45:27 +00003778 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003779 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003780 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003781 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003782 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003783 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003784 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003785 __u32 parm_len;
3786 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003787 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003788 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003789
3790/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003791 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003792 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003793 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003794 goto qsec_out;
3795 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3796
Joe Perchesf96637b2013-05-04 22:12:25 -05003797 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3798 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003799
3800 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3801 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003802 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003803 goto qsec_out;
3804 }
3805
3806/* BB check that data area is minimum length and as big as acl_len */
3807
Steve Frenchaf6f4612007-10-16 18:40:37 +00003808 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003809 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003810 cifs_dbg(VFS, "acl length %d does not match %d\n",
3811 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003812 if (*pbuflen > acl_len)
3813 *pbuflen = acl_len;
3814 }
Steve French0a4b92c2006-01-12 15:44:21 -08003815
Steve French630f3f0c2007-10-25 21:17:17 +00003816 /* check if buffer is big enough for the acl
3817 header followed by the smallest SID */
3818 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3819 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003820 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003821 rc = -EINVAL;
3822 *pbuflen = 0;
3823 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003824 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003825 if (*acl_inf == NULL) {
3826 *pbuflen = 0;
3827 rc = -ENOMEM;
3828 }
Steve French630f3f0c2007-10-25 21:17:17 +00003829 }
Steve French0a4b92c2006-01-12 15:44:21 -08003830 }
3831qsec_out:
Sachin Prabhu6d81ed12014-06-16 15:35:24 +01003832 free_rsp_buf(buf_type, iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003833/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003834 return rc;
3835}
Steve French97837582007-12-31 07:47:21 +00003836
3837int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003838CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003839 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003840{
3841 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3842 int rc = 0;
3843 int bytes_returned = 0;
3844 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003845 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003846
3847setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003848 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003849 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003850 return rc;
Steve French97837582007-12-31 07:47:21 +00003851
3852 pSMB->MaxSetupCount = 0;
3853 pSMB->Reserved = 0;
3854
3855 param_count = 8;
3856 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3857 data_count = acllen;
3858 data_offset = param_offset + param_count;
3859 byte_count = 3 /* pad */ + param_count;
3860
3861 pSMB->DataCount = cpu_to_le32(data_count);
3862 pSMB->TotalDataCount = pSMB->DataCount;
3863 pSMB->MaxParameterCount = cpu_to_le32(4);
3864 pSMB->MaxDataCount = cpu_to_le32(16384);
3865 pSMB->ParameterCount = cpu_to_le32(param_count);
3866 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3867 pSMB->TotalParameterCount = pSMB->ParameterCount;
3868 pSMB->DataOffset = cpu_to_le32(data_offset);
3869 pSMB->SetupCount = 0;
3870 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3871 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3872
3873 pSMB->Fid = fid; /* file handle always le */
3874 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003875 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003876
3877 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003878 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3879 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003880 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003881 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003882 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003883
3884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3886
Joe Perchesf96637b2013-05-04 22:12:25 -05003887 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3888 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003889 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003890 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003891 cifs_buf_release(pSMB);
3892
3893 if (rc == -EAGAIN)
3894 goto setCifsAclRetry;
3895
3896 return (rc);
3897}
3898
Jeff Layton79df1ba2010-12-06 12:52:08 -05003899#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003900
Steve French6b8edfe2005-08-23 20:26:03 -07003901/* Legacy Query Path Information call for lookup to old servers such
3902 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003903int
3904SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3905 const char *search_name, FILE_ALL_INFO *data,
3906 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003907{
Steve Frenchad7a2922008-02-07 23:25:02 +00003908 QUERY_INFORMATION_REQ *pSMB;
3909 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003910 int rc = 0;
3911 int bytes_returned;
3912 int name_len;
3913
Joe Perchesf96637b2013-05-04 22:12:25 -05003914 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003915QInfRetry:
3916 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003917 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003918 if (rc)
3919 return rc;
3920
3921 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3922 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003923 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003924 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003925 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003926 name_len++; /* trailing null */
3927 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003928 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003929 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003930 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003931 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003932 }
3933 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003934 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003935 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003936 pSMB->ByteCount = cpu_to_le16(name_len);
3937
3938 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003939 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003940 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003941 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003942 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003943 struct timespec ts;
3944 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003945
3946 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003947 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003948 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003949 ts.tv_nsec = 0;
3950 ts.tv_sec = time;
3951 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003952 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3953 data->LastWriteTime = data->ChangeTime;
3954 data->LastAccessTime = 0;
3955 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003956 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003957 data->EndOfFile = data->AllocationSize;
3958 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003959 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003960 } else
3961 rc = -EIO; /* bad buffer passed in */
3962
3963 cifs_buf_release(pSMB);
3964
3965 if (rc == -EAGAIN)
3966 goto QInfRetry;
3967
3968 return rc;
3969}
3970
Jeff Laytonbcd53572010-02-12 07:44:16 -05003971int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003972CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003973 u16 netfid, FILE_ALL_INFO *pFindData)
3974{
3975 struct smb_t2_qfi_req *pSMB = NULL;
3976 struct smb_t2_qfi_rsp *pSMBr = NULL;
3977 int rc = 0;
3978 int bytes_returned;
3979 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003980
Jeff Laytonbcd53572010-02-12 07:44:16 -05003981QFileInfoRetry:
3982 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3983 (void **) &pSMBr);
3984 if (rc)
3985 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003986
Jeff Laytonbcd53572010-02-12 07:44:16 -05003987 params = 2 /* level */ + 2 /* fid */;
3988 pSMB->t2.TotalDataCount = 0;
3989 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3990 /* BB find exact max data count below from sess structure BB */
3991 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3992 pSMB->t2.MaxSetupCount = 0;
3993 pSMB->t2.Reserved = 0;
3994 pSMB->t2.Flags = 0;
3995 pSMB->t2.Timeout = 0;
3996 pSMB->t2.Reserved2 = 0;
3997 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3998 Fid) - 4);
3999 pSMB->t2.DataCount = 0;
4000 pSMB->t2.DataOffset = 0;
4001 pSMB->t2.SetupCount = 1;
4002 pSMB->t2.Reserved3 = 0;
4003 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4004 byte_count = params + 1 /* pad */ ;
4005 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4006 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4007 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4008 pSMB->Pad = 0;
4009 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004010 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004011 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004012
4013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4015 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004016 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004017 } else { /* decode response */
4018 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4019
4020 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4021 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004022 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004023 rc = -EIO; /* bad smb */
4024 else if (pFindData) {
4025 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4026 memcpy((char *) pFindData,
4027 (char *) &pSMBr->hdr.Protocol +
4028 data_offset, sizeof(FILE_ALL_INFO));
4029 } else
4030 rc = -ENOMEM;
4031 }
4032 cifs_buf_release(pSMB);
4033 if (rc == -EAGAIN)
4034 goto QFileInfoRetry;
4035
4036 return rc;
4037}
Steve French6b8edfe2005-08-23 20:26:03 -07004038
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004040CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004041 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004042 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004043 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004045 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 TRANSACTION2_QPI_REQ *pSMB = NULL;
4047 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4048 int rc = 0;
4049 int bytes_returned;
4050 int name_len;
4051 __u16 params, byte_count;
4052
Joe Perchesf96637b2013-05-04 22:12:25 -05004053 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054QPathInfoRetry:
4055 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4056 (void **) &pSMBr);
4057 if (rc)
4058 return rc;
4059
4060 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4061 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004062 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004063 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 name_len++; /* trailing null */
4065 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004066 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004067 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004069 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 }
4071
Steve French50c2f752007-07-13 00:33:32 +00004072 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 pSMB->TotalDataCount = 0;
4074 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004075 /* BB find exact max SMB PDU from sess structure BB */
4076 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 pSMB->MaxSetupCount = 0;
4078 pSMB->Reserved = 0;
4079 pSMB->Flags = 0;
4080 pSMB->Timeout = 0;
4081 pSMB->Reserved2 = 0;
4082 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004083 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 pSMB->DataCount = 0;
4085 pSMB->DataOffset = 0;
4086 pSMB->SetupCount = 1;
4087 pSMB->Reserved3 = 0;
4088 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4089 byte_count = params + 1 /* pad */ ;
4090 pSMB->TotalParameterCount = cpu_to_le16(params);
4091 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004092 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004093 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4094 else
4095 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004097 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 pSMB->ByteCount = cpu_to_le16(byte_count);
4099
4100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4102 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004103 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 } else { /* decode response */
4105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4106
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004107 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4108 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004109 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004111 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004112 rc = -EIO; /* 24 or 26 expected but we do not read
4113 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004114 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004115 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004117
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004118 /*
4119 * On legacy responses we do not read the last field,
4120 * EAsize, fortunately since it varies by subdialect and
4121 * also note it differs on Set vs Get, ie two bytes or 4
4122 * bytes depending but we don't care here.
4123 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004124 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004125 size = sizeof(FILE_INFO_STANDARD);
4126 else
4127 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004128 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004129 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 } else
4131 rc = -ENOMEM;
4132 }
4133 cifs_buf_release(pSMB);
4134 if (rc == -EAGAIN)
4135 goto QPathInfoRetry;
4136
4137 return rc;
4138}
4139
4140int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004141CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004142 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4143{
4144 struct smb_t2_qfi_req *pSMB = NULL;
4145 struct smb_t2_qfi_rsp *pSMBr = NULL;
4146 int rc = 0;
4147 int bytes_returned;
4148 __u16 params, byte_count;
4149
4150UnixQFileInfoRetry:
4151 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4152 (void **) &pSMBr);
4153 if (rc)
4154 return rc;
4155
4156 params = 2 /* level */ + 2 /* fid */;
4157 pSMB->t2.TotalDataCount = 0;
4158 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4159 /* BB find exact max data count below from sess structure BB */
4160 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4161 pSMB->t2.MaxSetupCount = 0;
4162 pSMB->t2.Reserved = 0;
4163 pSMB->t2.Flags = 0;
4164 pSMB->t2.Timeout = 0;
4165 pSMB->t2.Reserved2 = 0;
4166 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4167 Fid) - 4);
4168 pSMB->t2.DataCount = 0;
4169 pSMB->t2.DataOffset = 0;
4170 pSMB->t2.SetupCount = 1;
4171 pSMB->t2.Reserved3 = 0;
4172 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4173 byte_count = params + 1 /* pad */ ;
4174 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4175 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4176 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4177 pSMB->Pad = 0;
4178 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004179 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004180 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004181
4182 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4183 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4184 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004185 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004186 } else { /* decode response */
4187 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4188
Jeff Layton820a8032011-05-04 08:05:26 -04004189 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004190 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 -05004191 rc = -EIO; /* bad smb */
4192 } else {
4193 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4194 memcpy((char *) pFindData,
4195 (char *) &pSMBr->hdr.Protocol +
4196 data_offset,
4197 sizeof(FILE_UNIX_BASIC_INFO));
4198 }
4199 }
4200
4201 cifs_buf_release(pSMB);
4202 if (rc == -EAGAIN)
4203 goto UnixQFileInfoRetry;
4204
4205 return rc;
4206}
4207
4208int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004209CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004211 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004212 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213{
4214/* SMB_QUERY_FILE_UNIX_BASIC */
4215 TRANSACTION2_QPI_REQ *pSMB = NULL;
4216 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4217 int rc = 0;
4218 int bytes_returned = 0;
4219 int name_len;
4220 __u16 params, byte_count;
4221
Joe Perchesf96637b2013-05-04 22:12:25 -05004222 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223UnixQPathInfoRetry:
4224 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4225 (void **) &pSMBr);
4226 if (rc)
4227 return rc;
4228
4229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4230 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004231 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4232 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 name_len++; /* trailing null */
4234 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004235 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 name_len = strnlen(searchName, PATH_MAX);
4237 name_len++; /* trailing null */
4238 strncpy(pSMB->FileName, searchName, name_len);
4239 }
4240
Steve French50c2f752007-07-13 00:33:32 +00004241 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 pSMB->TotalDataCount = 0;
4243 pSMB->MaxParameterCount = cpu_to_le16(2);
4244 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004245 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 pSMB->MaxSetupCount = 0;
4247 pSMB->Reserved = 0;
4248 pSMB->Flags = 0;
4249 pSMB->Timeout = 0;
4250 pSMB->Reserved2 = 0;
4251 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004252 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 pSMB->DataCount = 0;
4254 pSMB->DataOffset = 0;
4255 pSMB->SetupCount = 1;
4256 pSMB->Reserved3 = 0;
4257 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4258 byte_count = params + 1 /* pad */ ;
4259 pSMB->TotalParameterCount = cpu_to_le16(params);
4260 pSMB->ParameterCount = pSMB->TotalParameterCount;
4261 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4262 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004263 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 pSMB->ByteCount = cpu_to_le16(byte_count);
4265
4266 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4267 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4268 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004269 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 } else { /* decode response */
4271 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4272
Jeff Layton820a8032011-05-04 08:05:26 -04004273 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004274 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 -07004275 rc = -EIO; /* bad smb */
4276 } else {
4277 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4278 memcpy((char *) pFindData,
4279 (char *) &pSMBr->hdr.Protocol +
4280 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004281 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 }
4283 }
4284 cifs_buf_release(pSMB);
4285 if (rc == -EAGAIN)
4286 goto UnixQPathInfoRetry;
4287
4288 return rc;
4289}
4290
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291/* xid, tcon, searchName and codepage are input parms, rest are returned */
4292int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004293CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004294 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004295 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004296 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297{
4298/* level 257 SMB_ */
4299 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4300 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004301 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 int rc = 0;
4303 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004304 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004306 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307
Joe Perchesf96637b2013-05-04 22:12:25 -05004308 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
4310findFirstRetry:
4311 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4312 (void **) &pSMBr);
4313 if (rc)
4314 return rc;
4315
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004316 nls_codepage = cifs_sb->local_nls;
4317 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4318
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4320 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004321 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4322 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004323 /* We can not add the asterik earlier in case
4324 it got remapped to 0xF03A as if it were part of the
4325 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004327 if (msearch) {
4328 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4329 pSMB->FileName[name_len+1] = 0;
4330 pSMB->FileName[name_len+2] = '*';
4331 pSMB->FileName[name_len+3] = 0;
4332 name_len += 4; /* now the trailing null */
4333 /* null terminate just in case */
4334 pSMB->FileName[name_len] = 0;
4335 pSMB->FileName[name_len+1] = 0;
4336 name_len += 2;
4337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 } else { /* BB add check for overrun of SMB buf BB */
4339 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004341 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 free buffer exit; BB */
4343 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004344 if (msearch) {
4345 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4346 pSMB->FileName[name_len+1] = '*';
4347 pSMB->FileName[name_len+2] = 0;
4348 name_len += 3;
4349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 }
4351
4352 params = 12 + name_len /* includes null */ ;
4353 pSMB->TotalDataCount = 0; /* no EAs */
4354 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004355 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 pSMB->MaxSetupCount = 0;
4357 pSMB->Reserved = 0;
4358 pSMB->Flags = 0;
4359 pSMB->Timeout = 0;
4360 pSMB->Reserved2 = 0;
4361 byte_count = params + 1 /* pad */ ;
4362 pSMB->TotalParameterCount = cpu_to_le16(params);
4363 pSMB->ParameterCount = pSMB->TotalParameterCount;
4364 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004365 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4366 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 pSMB->DataCount = 0;
4368 pSMB->DataOffset = 0;
4369 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4370 pSMB->Reserved3 = 0;
4371 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4372 pSMB->SearchAttributes =
4373 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4374 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004375 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004376 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4378
4379 /* BB what should we set StorageType to? Does it matter? BB */
4380 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004381 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 pSMB->ByteCount = cpu_to_le16(byte_count);
4383
4384 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4385 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004386 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387
Steve French88274812006-03-09 22:21:45 +00004388 if (rc) {/* BB add logic to retry regular search if Unix search
4389 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004391 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004392
Steve French88274812006-03-09 22:21:45 +00004393 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
4395 /* BB eventually could optimize out free and realloc of buf */
4396 /* for this case */
4397 if (rc == -EAGAIN)
4398 goto findFirstRetry;
4399 } else { /* decode response */
4400 /* BB remember to free buffer if error BB */
4401 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004402 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004403 unsigned int lnoff;
4404
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004406 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 else
Steve French4b18f2a2008-04-29 00:06:05 +00004408 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
4410 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004411 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004412 psrch_inf->srch_entries_start =
4413 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4416 le16_to_cpu(pSMBr->t2.ParameterOffset));
4417
Steve French790fe572007-07-07 19:25:05 +00004418 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004419 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 else
Steve French4b18f2a2008-04-29 00:06:05 +00004421 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
Steve French50c2f752007-07-13 00:33:32 +00004423 psrch_inf->entries_in_buffer =
4424 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004425 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004427 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004428 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004429 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004430 psrch_inf->last_entry = NULL;
4431 return rc;
4432 }
4433
Steve French0752f152008-10-07 20:03:33 +00004434 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004435 lnoff;
4436
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004437 if (pnetfid)
4438 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 } else {
4440 cifs_buf_release(pSMB);
4441 }
4442 }
4443
4444 return rc;
4445}
4446
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004447int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4448 __u16 searchHandle, __u16 search_flags,
4449 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450{
4451 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4452 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004453 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 char *response_data;
4455 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004456 int bytes_returned;
4457 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 __u16 params, byte_count;
4459
Joe Perchesf96637b2013-05-04 22:12:25 -05004460 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
Steve French4b18f2a2008-04-29 00:06:05 +00004462 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 return -ENOENT;
4464
4465 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4466 (void **) &pSMBr);
4467 if (rc)
4468 return rc;
4469
Steve French50c2f752007-07-13 00:33:32 +00004470 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 byte_count = 0;
4472 pSMB->TotalDataCount = 0; /* no EAs */
4473 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004474 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 pSMB->MaxSetupCount = 0;
4476 pSMB->Reserved = 0;
4477 pSMB->Flags = 0;
4478 pSMB->Timeout = 0;
4479 pSMB->Reserved2 = 0;
4480 pSMB->ParameterOffset = cpu_to_le16(
4481 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4482 pSMB->DataCount = 0;
4483 pSMB->DataOffset = 0;
4484 pSMB->SetupCount = 1;
4485 pSMB->Reserved3 = 0;
4486 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4487 pSMB->SearchHandle = searchHandle; /* always kept as le */
4488 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004489 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4491 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004492 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
4494 name_len = psrch_inf->resume_name_len;
4495 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004496 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4498 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004499 /* 14 byte parm len above enough for 2 byte null terminator */
4500 pSMB->ResumeFileName[name_len] = 0;
4501 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 } else {
4503 rc = -EINVAL;
4504 goto FNext2_err_exit;
4505 }
4506 byte_count = params + 1 /* pad */ ;
4507 pSMB->TotalParameterCount = cpu_to_le16(params);
4508 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004509 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004511
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4513 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004514 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 if (rc) {
4516 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004517 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004518 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004519 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004521 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 } else { /* decode response */
4523 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004524
Steve French790fe572007-07-07 19:25:05 +00004525 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004526 unsigned int lnoff;
4527
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 /* BB fixme add lock for file (srch_info) struct here */
4529 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004530 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 else
Steve French4b18f2a2008-04-29 00:06:05 +00004532 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 response_data = (char *) &pSMBr->hdr.Protocol +
4534 le16_to_cpu(pSMBr->t2.ParameterOffset);
4535 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4536 response_data = (char *)&pSMBr->hdr.Protocol +
4537 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004538 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004539 cifs_small_buf_release(
4540 psrch_inf->ntwrk_buf_start);
4541 else
4542 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 psrch_inf->srch_entries_start = response_data;
4544 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004545 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004546 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004547 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 else
Steve French4b18f2a2008-04-29 00:06:05 +00004549 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004550 psrch_inf->entries_in_buffer =
4551 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 psrch_inf->index_of_last_entry +=
4553 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004554 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004555 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004556 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004557 psrch_inf->last_entry = NULL;
4558 return rc;
4559 } else
4560 psrch_inf->last_entry =
4561 psrch_inf->srch_entries_start + lnoff;
4562
Joe Perchesf96637b2013-05-04 22:12:25 -05004563/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4564 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565
4566 /* BB fixme add unlock here */
4567 }
4568
4569 }
4570
4571 /* BB On error, should we leave previous search buf (and count and
4572 last entry fields) intact or free the previous one? */
4573
4574 /* Note: On -EAGAIN error only caller can retry on handle based calls
4575 since file handle passed in no longer valid */
4576FNext2_err_exit:
4577 if (rc != 0)
4578 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 return rc;
4580}
4581
4582int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004583CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004584 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585{
4586 int rc = 0;
4587 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
Joe Perchesf96637b2013-05-04 22:12:25 -05004589 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4591
4592 /* no sense returning error if session restarted
4593 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004594 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 return 0;
4596 if (rc)
4597 return rc;
4598
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 pSMB->FileID = searchHandle;
4600 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004601 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004602 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004603 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004604
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004605 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606
4607 /* Since session is dead, search handle closed on server already */
4608 if (rc == -EAGAIN)
4609 rc = 0;
4610
4611 return rc;
4612}
4613
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004615CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004616 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004617 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618{
4619 int rc = 0;
4620 TRANSACTION2_QPI_REQ *pSMB = NULL;
4621 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4622 int name_len, bytes_returned;
4623 __u16 params, byte_count;
4624
Joe Perchesf96637b2013-05-04 22:12:25 -05004625 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004626 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004627 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628
4629GetInodeNumberRetry:
4630 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004631 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 if (rc)
4633 return rc;
4634
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4636 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004637 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004638 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004639 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 name_len++; /* trailing null */
4641 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004642 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004643 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004645 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 }
4647
4648 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4649 pSMB->TotalDataCount = 0;
4650 pSMB->MaxParameterCount = cpu_to_le16(2);
4651 /* BB find exact max data count below from sess structure BB */
4652 pSMB->MaxDataCount = cpu_to_le16(4000);
4653 pSMB->MaxSetupCount = 0;
4654 pSMB->Reserved = 0;
4655 pSMB->Flags = 0;
4656 pSMB->Timeout = 0;
4657 pSMB->Reserved2 = 0;
4658 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004659 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 pSMB->DataCount = 0;
4661 pSMB->DataOffset = 0;
4662 pSMB->SetupCount = 1;
4663 pSMB->Reserved3 = 0;
4664 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4665 byte_count = params + 1 /* pad */ ;
4666 pSMB->TotalParameterCount = cpu_to_le16(params);
4667 pSMB->ParameterCount = pSMB->TotalParameterCount;
4668 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4669 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004670 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 pSMB->ByteCount = cpu_to_le16(byte_count);
4672
4673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4675 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004676 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 } else {
4678 /* decode response */
4679 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004681 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 /* If rc should we check for EOPNOSUPP and
4683 disable the srvino flag? or in caller? */
4684 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004685 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4687 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004688 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004690 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004691 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 rc = -EIO;
4693 goto GetInodeNumOut;
4694 }
4695 pfinfo = (struct file_internal_info *)
4696 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004697 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 }
4699 }
4700GetInodeNumOut:
4701 cifs_buf_release(pSMB);
4702 if (rc == -EAGAIN)
4703 goto GetInodeNumberRetry;
4704 return rc;
4705}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
Igor Mammedovfec45852008-05-16 13:06:30 +04004707/* parses DFS refferal V3 structure
4708 * caller is responsible for freeing target_nodes
4709 * returns:
4710 * on success - 0
4711 * on failure - errno
4712 */
4713static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004714parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004715 unsigned int *num_of_nodes,
4716 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004717 const struct nls_table *nls_codepage, int remap,
4718 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004719{
4720 int i, rc = 0;
4721 char *data_end;
4722 bool is_unicode;
4723 struct dfs_referral_level_3 *ref;
4724
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004725 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4726 is_unicode = true;
4727 else
4728 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004729 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4730
4731 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004732 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4733 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004734 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004735 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004736 }
4737
4738 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004739 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004740 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4741 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004742 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004743 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004744 }
4745
4746 /* get the upper boundary of the resp buffer */
4747 data_end = (char *)(&(pSMBr->PathConsumed)) +
4748 le16_to_cpu(pSMBr->t2.DataCount);
4749
Joe Perchesf96637b2013-05-04 22:12:25 -05004750 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4751 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004752
Joe Perchesf96637b2013-05-04 22:12:25 -05004753 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4754 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004755 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004756 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004757 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004758 }
4759
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004760 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004761 for (i = 0; i < *num_of_nodes; i++) {
4762 char *temp;
4763 int max_len;
4764 struct dfs_info3_param *node = (*target_nodes)+i;
4765
Steve French0e0d2cf2009-05-01 05:27:32 +00004766 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004767 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004768 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4769 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004770 if (tmp == NULL) {
4771 rc = -ENOMEM;
4772 goto parse_DFS_referrals_exit;
4773 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004774 cifsConvertToUTF16((__le16 *) tmp, searchName,
4775 PATH_MAX, nls_codepage, remap);
4776 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004777 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004778 nls_codepage);
4779 kfree(tmp);
4780 } else
4781 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4782
Igor Mammedovfec45852008-05-16 13:06:30 +04004783 node->server_type = le16_to_cpu(ref->ServerType);
4784 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4785
4786 /* copy DfsPath */
4787 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4788 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004789 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4790 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004791 if (!node->path_name) {
4792 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004793 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004794 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004795
4796 /* copy link target UNC */
4797 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4798 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004799 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4800 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004801 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004802 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004803 goto parse_DFS_referrals_exit;
4804 }
4805
4806 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004807 }
4808
Steve Frencha1fe78f2008-05-16 18:48:38 +00004809parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004810 if (rc) {
4811 free_dfs_info_array(*target_nodes, *num_of_nodes);
4812 *target_nodes = NULL;
4813 *num_of_nodes = 0;
4814 }
4815 return rc;
4816}
4817
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004819CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004820 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004821 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004822 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823{
4824/* TRANS2_GET_DFS_REFERRAL */
4825 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4826 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 int rc = 0;
4828 int bytes_returned;
4829 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004831 *num_of_nodes = 0;
4832 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
Joe Perchesf96637b2013-05-04 22:12:25 -05004834 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 if (ses == NULL)
4836 return -ENODEV;
4837getDFSRetry:
4838 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4839 (void **) &pSMBr);
4840 if (rc)
4841 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004842
4843 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004844 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004845 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 pSMB->hdr.Tid = ses->ipc_tid;
4847 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004848 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004850 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
4853 if (ses->capabilities & CAP_UNICODE) {
4854 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4855 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004856 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004857 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004858 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 name_len++; /* trailing null */
4860 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004861 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004862 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004864 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 }
4866
Jeff Layton38d77c52013-05-26 07:01:00 -04004867 if (ses->server && ses->server->sign)
4868 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004869
Steve French50c2f752007-07-13 00:33:32 +00004870 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004871
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 params = 2 /* level */ + name_len /*includes null */ ;
4873 pSMB->TotalDataCount = 0;
4874 pSMB->DataCount = 0;
4875 pSMB->DataOffset = 0;
4876 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004877 /* BB find exact max SMB PDU from sess structure BB */
4878 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 pSMB->MaxSetupCount = 0;
4880 pSMB->Reserved = 0;
4881 pSMB->Flags = 0;
4882 pSMB->Timeout = 0;
4883 pSMB->Reserved2 = 0;
4884 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004885 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 pSMB->SetupCount = 1;
4887 pSMB->Reserved3 = 0;
4888 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4889 byte_count = params + 3 /* pad */ ;
4890 pSMB->ParameterCount = cpu_to_le16(params);
4891 pSMB->TotalParameterCount = pSMB->ParameterCount;
4892 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004893 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 pSMB->ByteCount = cpu_to_le16(byte_count);
4895
4896 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4898 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004899 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004900 goto GetDFSRefExit;
4901 }
4902 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004904 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004905 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004906 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004907 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004909
Joe Perchesf96637b2013-05-04 22:12:25 -05004910 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4911 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004912
4913 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004914 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004915 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004916 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004917
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004919 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920
4921 if (rc == -EAGAIN)
4922 goto getDFSRetry;
4923
4924 return rc;
4925}
4926
Steve French20962432005-09-21 22:05:57 -07004927/* Query File System Info such as free space to old servers such as Win 9x */
4928int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004929SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4930 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004931{
4932/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4933 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4934 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4935 FILE_SYSTEM_ALLOC_INFO *response_data;
4936 int rc = 0;
4937 int bytes_returned = 0;
4938 __u16 params, byte_count;
4939
Joe Perchesf96637b2013-05-04 22:12:25 -05004940 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004941oldQFSInfoRetry:
4942 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4943 (void **) &pSMBr);
4944 if (rc)
4945 return rc;
Steve French20962432005-09-21 22:05:57 -07004946
4947 params = 2; /* level */
4948 pSMB->TotalDataCount = 0;
4949 pSMB->MaxParameterCount = cpu_to_le16(2);
4950 pSMB->MaxDataCount = cpu_to_le16(1000);
4951 pSMB->MaxSetupCount = 0;
4952 pSMB->Reserved = 0;
4953 pSMB->Flags = 0;
4954 pSMB->Timeout = 0;
4955 pSMB->Reserved2 = 0;
4956 byte_count = params + 1 /* pad */ ;
4957 pSMB->TotalParameterCount = cpu_to_le16(params);
4958 pSMB->ParameterCount = pSMB->TotalParameterCount;
4959 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4960 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4961 pSMB->DataCount = 0;
4962 pSMB->DataOffset = 0;
4963 pSMB->SetupCount = 1;
4964 pSMB->Reserved3 = 0;
4965 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4966 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004967 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004968 pSMB->ByteCount = cpu_to_le16(byte_count);
4969
4970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4971 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4972 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004973 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004974 } else { /* decode response */
4975 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4976
Jeff Layton820a8032011-05-04 08:05:26 -04004977 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004978 rc = -EIO; /* bad smb */
4979 else {
4980 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004981 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004982 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004983
Steve French50c2f752007-07-13 00:33:32 +00004984 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004985 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4986 FSData->f_bsize =
4987 le16_to_cpu(response_data->BytesPerSector) *
4988 le32_to_cpu(response_data->
4989 SectorsPerAllocationUnit);
4990 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004991 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004992 FSData->f_bfree = FSData->f_bavail =
4993 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004994 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4995 (unsigned long long)FSData->f_blocks,
4996 (unsigned long long)FSData->f_bfree,
4997 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004998 }
4999 }
5000 cifs_buf_release(pSMB);
5001
5002 if (rc == -EAGAIN)
5003 goto oldQFSInfoRetry;
5004
5005 return rc;
5006}
5007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005009CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5010 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011{
5012/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5013 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5014 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5015 FILE_SYSTEM_INFO *response_data;
5016 int rc = 0;
5017 int bytes_returned = 0;
5018 __u16 params, byte_count;
5019
Joe Perchesf96637b2013-05-04 22:12:25 -05005020 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021QFSInfoRetry:
5022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5023 (void **) &pSMBr);
5024 if (rc)
5025 return rc;
5026
5027 params = 2; /* level */
5028 pSMB->TotalDataCount = 0;
5029 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005030 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 pSMB->MaxSetupCount = 0;
5032 pSMB->Reserved = 0;
5033 pSMB->Flags = 0;
5034 pSMB->Timeout = 0;
5035 pSMB->Reserved2 = 0;
5036 byte_count = params + 1 /* pad */ ;
5037 pSMB->TotalParameterCount = cpu_to_le16(params);
5038 pSMB->ParameterCount = pSMB->TotalParameterCount;
5039 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005040 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 pSMB->DataCount = 0;
5042 pSMB->DataOffset = 0;
5043 pSMB->SetupCount = 1;
5044 pSMB->Reserved3 = 0;
5045 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5046 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005047 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 pSMB->ByteCount = cpu_to_le16(byte_count);
5049
5050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5052 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005053 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005055 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Jeff Layton820a8032011-05-04 08:05:26 -04005057 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 rc = -EIO; /* bad smb */
5059 else {
5060 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061
5062 response_data =
5063 (FILE_SYSTEM_INFO
5064 *) (((char *) &pSMBr->hdr.Protocol) +
5065 data_offset);
5066 FSData->f_bsize =
5067 le32_to_cpu(response_data->BytesPerSector) *
5068 le32_to_cpu(response_data->
5069 SectorsPerAllocationUnit);
5070 FSData->f_blocks =
5071 le64_to_cpu(response_data->TotalAllocationUnits);
5072 FSData->f_bfree = FSData->f_bavail =
5073 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005074 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5075 (unsigned long long)FSData->f_blocks,
5076 (unsigned long long)FSData->f_bfree,
5077 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 }
5079 }
5080 cifs_buf_release(pSMB);
5081
5082 if (rc == -EAGAIN)
5083 goto QFSInfoRetry;
5084
5085 return rc;
5086}
5087
5088int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005089CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090{
5091/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5092 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5093 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5094 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5095 int rc = 0;
5096 int bytes_returned = 0;
5097 __u16 params, byte_count;
5098
Joe Perchesf96637b2013-05-04 22:12:25 -05005099 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100QFSAttributeRetry:
5101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5102 (void **) &pSMBr);
5103 if (rc)
5104 return rc;
5105
5106 params = 2; /* level */
5107 pSMB->TotalDataCount = 0;
5108 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005109 /* BB find exact max SMB PDU from sess structure BB */
5110 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 pSMB->MaxSetupCount = 0;
5112 pSMB->Reserved = 0;
5113 pSMB->Flags = 0;
5114 pSMB->Timeout = 0;
5115 pSMB->Reserved2 = 0;
5116 byte_count = params + 1 /* pad */ ;
5117 pSMB->TotalParameterCount = cpu_to_le16(params);
5118 pSMB->ParameterCount = pSMB->TotalParameterCount;
5119 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005120 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 pSMB->DataCount = 0;
5122 pSMB->DataOffset = 0;
5123 pSMB->SetupCount = 1;
5124 pSMB->Reserved3 = 0;
5125 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5126 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005127 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 pSMB->ByteCount = cpu_to_le16(byte_count);
5129
5130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5132 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005133 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 } else { /* decode response */
5135 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5136
Jeff Layton820a8032011-05-04 08:05:26 -04005137 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005138 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 rc = -EIO; /* bad smb */
5140 } else {
5141 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5142 response_data =
5143 (FILE_SYSTEM_ATTRIBUTE_INFO
5144 *) (((char *) &pSMBr->hdr.Protocol) +
5145 data_offset);
5146 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005147 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 }
5149 }
5150 cifs_buf_release(pSMB);
5151
5152 if (rc == -EAGAIN)
5153 goto QFSAttributeRetry;
5154
5155 return rc;
5156}
5157
5158int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005159CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160{
5161/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5162 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5163 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5164 FILE_SYSTEM_DEVICE_INFO *response_data;
5165 int rc = 0;
5166 int bytes_returned = 0;
5167 __u16 params, byte_count;
5168
Joe Perchesf96637b2013-05-04 22:12:25 -05005169 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170QFSDeviceRetry:
5171 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5172 (void **) &pSMBr);
5173 if (rc)
5174 return rc;
5175
5176 params = 2; /* level */
5177 pSMB->TotalDataCount = 0;
5178 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005179 /* BB find exact max SMB PDU from sess structure BB */
5180 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 pSMB->MaxSetupCount = 0;
5182 pSMB->Reserved = 0;
5183 pSMB->Flags = 0;
5184 pSMB->Timeout = 0;
5185 pSMB->Reserved2 = 0;
5186 byte_count = params + 1 /* pad */ ;
5187 pSMB->TotalParameterCount = cpu_to_le16(params);
5188 pSMB->ParameterCount = pSMB->TotalParameterCount;
5189 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005190 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191
5192 pSMB->DataCount = 0;
5193 pSMB->DataOffset = 0;
5194 pSMB->SetupCount = 1;
5195 pSMB->Reserved3 = 0;
5196 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5197 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005198 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 pSMB->ByteCount = cpu_to_le16(byte_count);
5200
5201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5203 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005204 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 } else { /* decode response */
5206 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5207
Jeff Layton820a8032011-05-04 08:05:26 -04005208 if (rc || get_bcc(&pSMBr->hdr) <
5209 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 rc = -EIO; /* bad smb */
5211 else {
5212 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5213 response_data =
Steve French737b7582005-04-28 22:41:06 -07005214 (FILE_SYSTEM_DEVICE_INFO *)
5215 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 data_offset);
5217 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005218 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 }
5220 }
5221 cifs_buf_release(pSMB);
5222
5223 if (rc == -EAGAIN)
5224 goto QFSDeviceRetry;
5225
5226 return rc;
5227}
5228
5229int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005230CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231{
5232/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5233 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5234 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5235 FILE_SYSTEM_UNIX_INFO *response_data;
5236 int rc = 0;
5237 int bytes_returned = 0;
5238 __u16 params, byte_count;
5239
Joe Perchesf96637b2013-05-04 22:12:25 -05005240 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005242 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5243 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 if (rc)
5245 return rc;
5246
5247 params = 2; /* level */
5248 pSMB->TotalDataCount = 0;
5249 pSMB->DataCount = 0;
5250 pSMB->DataOffset = 0;
5251 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005252 /* BB find exact max SMB PDU from sess structure BB */
5253 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 pSMB->MaxSetupCount = 0;
5255 pSMB->Reserved = 0;
5256 pSMB->Flags = 0;
5257 pSMB->Timeout = 0;
5258 pSMB->Reserved2 = 0;
5259 byte_count = params + 1 /* pad */ ;
5260 pSMB->ParameterCount = cpu_to_le16(params);
5261 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005262 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5263 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 pSMB->SetupCount = 1;
5265 pSMB->Reserved3 = 0;
5266 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5267 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005268 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269 pSMB->ByteCount = cpu_to_le16(byte_count);
5270
5271 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5272 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5273 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005274 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 } else { /* decode response */
5276 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5277
Jeff Layton820a8032011-05-04 08:05:26 -04005278 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 rc = -EIO; /* bad smb */
5280 } else {
5281 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5282 response_data =
5283 (FILE_SYSTEM_UNIX_INFO
5284 *) (((char *) &pSMBr->hdr.Protocol) +
5285 data_offset);
5286 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005287 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 }
5289 }
5290 cifs_buf_release(pSMB);
5291
5292 if (rc == -EAGAIN)
5293 goto QFSUnixRetry;
5294
5295
5296 return rc;
5297}
5298
Jeremy Allisonac670552005-06-22 17:26:35 -07005299int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005300CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005301{
5302/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5303 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5304 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5305 int rc = 0;
5306 int bytes_returned = 0;
5307 __u16 params, param_offset, offset, byte_count;
5308
Joe Perchesf96637b2013-05-04 22:12:25 -05005309 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005310SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005311 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005312 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5313 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005314 if (rc)
5315 return rc;
5316
5317 params = 4; /* 2 bytes zero followed by info level. */
5318 pSMB->MaxSetupCount = 0;
5319 pSMB->Reserved = 0;
5320 pSMB->Flags = 0;
5321 pSMB->Timeout = 0;
5322 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005323 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5324 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005325 offset = param_offset + params;
5326
5327 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005328 /* BB find exact max SMB PDU from sess structure BB */
5329 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005330 pSMB->SetupCount = 1;
5331 pSMB->Reserved3 = 0;
5332 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5333 byte_count = 1 /* pad */ + params + 12;
5334
5335 pSMB->DataCount = cpu_to_le16(12);
5336 pSMB->ParameterCount = cpu_to_le16(params);
5337 pSMB->TotalDataCount = pSMB->DataCount;
5338 pSMB->TotalParameterCount = pSMB->ParameterCount;
5339 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5340 pSMB->DataOffset = cpu_to_le16(offset);
5341
5342 /* Params. */
5343 pSMB->FileNum = 0;
5344 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5345
5346 /* Data. */
5347 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5348 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5349 pSMB->ClientUnixCap = cpu_to_le64(cap);
5350
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005351 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005352 pSMB->ByteCount = cpu_to_le16(byte_count);
5353
5354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5356 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005357 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005358 } else { /* decode response */
5359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005360 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005361 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005362 }
5363 cifs_buf_release(pSMB);
5364
5365 if (rc == -EAGAIN)
5366 goto SETFSUnixRetry;
5367
5368 return rc;
5369}
5370
5371
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372
5373int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005374CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005375 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376{
5377/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5378 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5379 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5380 FILE_SYSTEM_POSIX_INFO *response_data;
5381 int rc = 0;
5382 int bytes_returned = 0;
5383 __u16 params, byte_count;
5384
Joe Perchesf96637b2013-05-04 22:12:25 -05005385 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386QFSPosixRetry:
5387 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5388 (void **) &pSMBr);
5389 if (rc)
5390 return rc;
5391
5392 params = 2; /* level */
5393 pSMB->TotalDataCount = 0;
5394 pSMB->DataCount = 0;
5395 pSMB->DataOffset = 0;
5396 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005397 /* BB find exact max SMB PDU from sess structure BB */
5398 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 pSMB->MaxSetupCount = 0;
5400 pSMB->Reserved = 0;
5401 pSMB->Flags = 0;
5402 pSMB->Timeout = 0;
5403 pSMB->Reserved2 = 0;
5404 byte_count = params + 1 /* pad */ ;
5405 pSMB->ParameterCount = cpu_to_le16(params);
5406 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005407 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5408 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 pSMB->SetupCount = 1;
5410 pSMB->Reserved3 = 0;
5411 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5412 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005413 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 pSMB->ByteCount = cpu_to_le16(byte_count);
5415
5416 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5417 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5418 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005419 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 } else { /* decode response */
5421 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5422
Jeff Layton820a8032011-05-04 08:05:26 -04005423 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 rc = -EIO; /* bad smb */
5425 } else {
5426 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5427 response_data =
5428 (FILE_SYSTEM_POSIX_INFO
5429 *) (((char *) &pSMBr->hdr.Protocol) +
5430 data_offset);
5431 FSData->f_bsize =
5432 le32_to_cpu(response_data->BlockSize);
5433 FSData->f_blocks =
5434 le64_to_cpu(response_data->TotalBlocks);
5435 FSData->f_bfree =
5436 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005437 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 FSData->f_bavail = FSData->f_bfree;
5439 } else {
5440 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005441 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 }
Steve French790fe572007-07-07 19:25:05 +00005443 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005445 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005446 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005448 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 }
5450 }
5451 cifs_buf_release(pSMB);
5452
5453 if (rc == -EAGAIN)
5454 goto QFSPosixRetry;
5455
5456 return rc;
5457}
5458
5459
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005460/*
5461 * We can not use write of zero bytes trick to set file size due to need for
5462 * large file support. Also note that this SetPathInfo is preferred to
5463 * SetFileInfo based method in next routine which is only needed to work around
5464 * a sharing violation bugin Samba which this routine can run into.
5465 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005467CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005468 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5469 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470{
5471 struct smb_com_transaction2_spi_req *pSMB = NULL;
5472 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5473 struct file_end_of_file_info *parm_data;
5474 int name_len;
5475 int rc = 0;
5476 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005477 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5478
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 __u16 params, byte_count, data_count, param_offset, offset;
5480
Joe Perchesf96637b2013-05-04 22:12:25 -05005481 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482SetEOFRetry:
5483 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5484 (void **) &pSMBr);
5485 if (rc)
5486 return rc;
5487
5488 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5489 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005490 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5491 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 name_len++; /* trailing null */
5493 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005494 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005495 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005497 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 }
5499 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005500 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005502 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 pSMB->MaxSetupCount = 0;
5504 pSMB->Reserved = 0;
5505 pSMB->Flags = 0;
5506 pSMB->Timeout = 0;
5507 pSMB->Reserved2 = 0;
5508 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005509 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005511 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005512 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5513 pSMB->InformationLevel =
5514 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5515 else
5516 pSMB->InformationLevel =
5517 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5518 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5520 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005521 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 else
5523 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005524 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 }
5526
5527 parm_data =
5528 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5529 offset);
5530 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5531 pSMB->DataOffset = cpu_to_le16(offset);
5532 pSMB->SetupCount = 1;
5533 pSMB->Reserved3 = 0;
5534 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5535 byte_count = 3 /* pad */ + params + data_count;
5536 pSMB->DataCount = cpu_to_le16(data_count);
5537 pSMB->TotalDataCount = pSMB->DataCount;
5538 pSMB->ParameterCount = cpu_to_le16(params);
5539 pSMB->TotalParameterCount = pSMB->ParameterCount;
5540 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005541 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 parm_data->FileSize = cpu_to_le64(size);
5543 pSMB->ByteCount = cpu_to_le16(byte_count);
5544 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5545 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005546 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005547 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548
5549 cifs_buf_release(pSMB);
5550
5551 if (rc == -EAGAIN)
5552 goto SetEOFRetry;
5553
5554 return rc;
5555}
5556
5557int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005558CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5559 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560{
5561 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 struct file_end_of_file_info *parm_data;
5563 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 __u16 params, param_offset, offset, byte_count, count;
5565
Joe Perchesf96637b2013-05-04 22:12:25 -05005566 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5567 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005568 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5569
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 if (rc)
5571 return rc;
5572
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005573 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5574 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005575
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 params = 6;
5577 pSMB->MaxSetupCount = 0;
5578 pSMB->Reserved = 0;
5579 pSMB->Flags = 0;
5580 pSMB->Timeout = 0;
5581 pSMB->Reserved2 = 0;
5582 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5583 offset = param_offset + params;
5584
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 count = sizeof(struct file_end_of_file_info);
5586 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005587 /* BB find exact max SMB PDU from sess structure BB */
5588 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 pSMB->SetupCount = 1;
5590 pSMB->Reserved3 = 0;
5591 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5592 byte_count = 3 /* pad */ + params + count;
5593 pSMB->DataCount = cpu_to_le16(count);
5594 pSMB->ParameterCount = cpu_to_le16(params);
5595 pSMB->TotalDataCount = pSMB->DataCount;
5596 pSMB->TotalParameterCount = pSMB->ParameterCount;
5597 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5598 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005599 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5600 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 pSMB->DataOffset = cpu_to_le16(offset);
5602 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005603 pSMB->Fid = cfile->fid.netfid;
5604 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5606 pSMB->InformationLevel =
5607 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5608 else
5609 pSMB->InformationLevel =
5610 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005611 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5613 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005614 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 else
5616 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005617 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 }
5619 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005620 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005622 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005624 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5625 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 }
5627
Steve French50c2f752007-07-13 00:33:32 +00005628 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 since file handle passed in no longer valid */
5630
5631 return rc;
5632}
5633
Steve French50c2f752007-07-13 00:33:32 +00005634/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 an open handle, rather than by pathname - this is awkward due to
5636 potential access conflicts on the open, but it is unavoidable for these
5637 old servers since the only other choice is to go from 100 nanosecond DCE
5638 time and resort to the original setpathinfo level which takes the ancient
5639 DOS time format with 2 second granularity */
5640int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005641CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005642 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643{
5644 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 char *data_offset;
5646 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 __u16 params, param_offset, offset, byte_count, count;
5648
Joe Perchesf96637b2013-05-04 22:12:25 -05005649 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005650 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5651
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 if (rc)
5653 return rc;
5654
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005655 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5656 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005657
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 params = 6;
5659 pSMB->MaxSetupCount = 0;
5660 pSMB->Reserved = 0;
5661 pSMB->Flags = 0;
5662 pSMB->Timeout = 0;
5663 pSMB->Reserved2 = 0;
5664 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5665 offset = param_offset + params;
5666
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005667 data_offset = (char *)pSMB +
5668 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Steve French26f57362007-08-30 22:09:15 +00005670 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005672 /* BB find max SMB PDU from sess */
5673 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 pSMB->SetupCount = 1;
5675 pSMB->Reserved3 = 0;
5676 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5677 byte_count = 3 /* pad */ + params + count;
5678 pSMB->DataCount = cpu_to_le16(count);
5679 pSMB->ParameterCount = cpu_to_le16(params);
5680 pSMB->TotalDataCount = pSMB->DataCount;
5681 pSMB->TotalParameterCount = pSMB->ParameterCount;
5682 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5683 pSMB->DataOffset = cpu_to_le16(offset);
5684 pSMB->Fid = fid;
5685 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5686 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5687 else
5688 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5689 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005690 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005692 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005693 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005694 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005695 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5696 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697
Steve French50c2f752007-07-13 00:33:32 +00005698 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 since file handle passed in no longer valid */
5700
5701 return rc;
5702}
5703
Jeff Layton6d22f092008-09-23 11:48:35 -04005704int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005705CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005706 bool delete_file, __u16 fid, __u32 pid_of_opener)
5707{
5708 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5709 char *data_offset;
5710 int rc = 0;
5711 __u16 params, param_offset, offset, byte_count, count;
5712
Joe Perchesf96637b2013-05-04 22:12:25 -05005713 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005714 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5715
5716 if (rc)
5717 return rc;
5718
5719 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5720 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5721
5722 params = 6;
5723 pSMB->MaxSetupCount = 0;
5724 pSMB->Reserved = 0;
5725 pSMB->Flags = 0;
5726 pSMB->Timeout = 0;
5727 pSMB->Reserved2 = 0;
5728 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5729 offset = param_offset + params;
5730
5731 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5732
5733 count = 1;
5734 pSMB->MaxParameterCount = cpu_to_le16(2);
5735 /* BB find max SMB PDU from sess */
5736 pSMB->MaxDataCount = cpu_to_le16(1000);
5737 pSMB->SetupCount = 1;
5738 pSMB->Reserved3 = 0;
5739 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5740 byte_count = 3 /* pad */ + params + count;
5741 pSMB->DataCount = cpu_to_le16(count);
5742 pSMB->ParameterCount = cpu_to_le16(params);
5743 pSMB->TotalDataCount = pSMB->DataCount;
5744 pSMB->TotalParameterCount = pSMB->ParameterCount;
5745 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5746 pSMB->DataOffset = cpu_to_le16(offset);
5747 pSMB->Fid = fid;
5748 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5749 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005750 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005751 pSMB->ByteCount = cpu_to_le16(byte_count);
5752 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005753 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005754 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005755 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005756
5757 return rc;
5758}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759
5760int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005761CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005762 const char *fileName, const FILE_BASIC_INFO *data,
5763 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764{
5765 TRANSACTION2_SPI_REQ *pSMB = NULL;
5766 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5767 int name_len;
5768 int rc = 0;
5769 int bytes_returned = 0;
5770 char *data_offset;
5771 __u16 params, param_offset, offset, byte_count, count;
5772
Joe Perchesf96637b2013-05-04 22:12:25 -05005773 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
5775SetTimesRetry:
5776 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5777 (void **) &pSMBr);
5778 if (rc)
5779 return rc;
5780
5781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5782 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005783 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5784 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 name_len++; /* trailing null */
5786 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005787 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 name_len = strnlen(fileName, PATH_MAX);
5789 name_len++; /* trailing null */
5790 strncpy(pSMB->FileName, fileName, name_len);
5791 }
5792
5793 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005794 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005796 /* BB find max SMB PDU from sess structure BB */
5797 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 pSMB->MaxSetupCount = 0;
5799 pSMB->Reserved = 0;
5800 pSMB->Flags = 0;
5801 pSMB->Timeout = 0;
5802 pSMB->Reserved2 = 0;
5803 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005804 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805 offset = param_offset + params;
5806 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5807 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5808 pSMB->DataOffset = cpu_to_le16(offset);
5809 pSMB->SetupCount = 1;
5810 pSMB->Reserved3 = 0;
5811 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5812 byte_count = 3 /* pad */ + params + count;
5813
5814 pSMB->DataCount = cpu_to_le16(count);
5815 pSMB->ParameterCount = cpu_to_le16(params);
5816 pSMB->TotalDataCount = pSMB->DataCount;
5817 pSMB->TotalParameterCount = pSMB->ParameterCount;
5818 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5819 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5820 else
5821 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5822 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005823 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005824 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 pSMB->ByteCount = cpu_to_le16(byte_count);
5826 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5827 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005828 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005829 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830
5831 cifs_buf_release(pSMB);
5832
5833 if (rc == -EAGAIN)
5834 goto SetTimesRetry;
5835
5836 return rc;
5837}
5838
5839/* Can not be used to set time stamps yet (due to old DOS time format) */
5840/* Can be used to set attributes */
5841#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5842 handling it anyway and NT4 was what we thought it would be needed for
5843 Do not delete it until we prove whether needed for Win9x though */
5844int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005845CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 __u16 dos_attrs, const struct nls_table *nls_codepage)
5847{
5848 SETATTR_REQ *pSMB = NULL;
5849 SETATTR_RSP *pSMBr = NULL;
5850 int rc = 0;
5851 int bytes_returned;
5852 int name_len;
5853
Joe Perchesf96637b2013-05-04 22:12:25 -05005854 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855
5856SetAttrLgcyRetry:
5857 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5858 (void **) &pSMBr);
5859 if (rc)
5860 return rc;
5861
5862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5863 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005864 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5865 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 name_len++; /* trailing null */
5867 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005868 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869 name_len = strnlen(fileName, PATH_MAX);
5870 name_len++; /* trailing null */
5871 strncpy(pSMB->fileName, fileName, name_len);
5872 }
5873 pSMB->attr = cpu_to_le16(dos_attrs);
5874 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005875 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005879 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005880 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881
5882 cifs_buf_release(pSMB);
5883
5884 if (rc == -EAGAIN)
5885 goto SetAttrLgcyRetry;
5886
5887 return rc;
5888}
5889#endif /* temporarily unneeded SetAttr legacy function */
5890
Jeff Layton654cf142009-07-09 20:02:49 -04005891static void
5892cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5893 const struct cifs_unix_set_info_args *args)
5894{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005895 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005896 u64 mode = args->mode;
5897
Eric W. Biederman49418b22013-02-06 00:57:56 -08005898 if (uid_valid(args->uid))
5899 uid = from_kuid(&init_user_ns, args->uid);
5900 if (gid_valid(args->gid))
5901 gid = from_kgid(&init_user_ns, args->gid);
5902
Jeff Layton654cf142009-07-09 20:02:49 -04005903 /*
5904 * Samba server ignores set of file size to zero due to bugs in some
5905 * older clients, but we should be precise - we use SetFileSize to
5906 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005907 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005908 * zero instead of -1 here
5909 */
5910 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5911 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5912 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5913 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5914 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005915 data_offset->Uid = cpu_to_le64(uid);
5916 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005917 /* better to leave device as zero when it is */
5918 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5919 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5920 data_offset->Permissions = cpu_to_le64(mode);
5921
5922 if (S_ISREG(mode))
5923 data_offset->Type = cpu_to_le32(UNIX_FILE);
5924 else if (S_ISDIR(mode))
5925 data_offset->Type = cpu_to_le32(UNIX_DIR);
5926 else if (S_ISLNK(mode))
5927 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5928 else if (S_ISCHR(mode))
5929 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5930 else if (S_ISBLK(mode))
5931 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5932 else if (S_ISFIFO(mode))
5933 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5934 else if (S_ISSOCK(mode))
5935 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5936}
5937
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005939CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005940 const struct cifs_unix_set_info_args *args,
5941 u16 fid, u32 pid_of_opener)
5942{
5943 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005944 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005945 int rc = 0;
5946 u16 params, param_offset, offset, byte_count, count;
5947
Joe Perchesf96637b2013-05-04 22:12:25 -05005948 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005949 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5950
5951 if (rc)
5952 return rc;
5953
5954 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5955 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5956
5957 params = 6;
5958 pSMB->MaxSetupCount = 0;
5959 pSMB->Reserved = 0;
5960 pSMB->Flags = 0;
5961 pSMB->Timeout = 0;
5962 pSMB->Reserved2 = 0;
5963 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5964 offset = param_offset + params;
5965
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005966 data_offset = (char *)pSMB +
5967 offsetof(struct smb_hdr, Protocol) + offset;
5968
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005969 count = sizeof(FILE_UNIX_BASIC_INFO);
5970
5971 pSMB->MaxParameterCount = cpu_to_le16(2);
5972 /* BB find max SMB PDU from sess */
5973 pSMB->MaxDataCount = cpu_to_le16(1000);
5974 pSMB->SetupCount = 1;
5975 pSMB->Reserved3 = 0;
5976 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5977 byte_count = 3 /* pad */ + params + count;
5978 pSMB->DataCount = cpu_to_le16(count);
5979 pSMB->ParameterCount = cpu_to_le16(params);
5980 pSMB->TotalDataCount = pSMB->DataCount;
5981 pSMB->TotalParameterCount = pSMB->ParameterCount;
5982 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5983 pSMB->DataOffset = cpu_to_le16(offset);
5984 pSMB->Fid = fid;
5985 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5986 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005987 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005988 pSMB->ByteCount = cpu_to_le16(byte_count);
5989
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005990 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005991
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005992 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005993 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005994 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5995 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005996
5997 /* Note: On -EAGAIN error only caller can retry on handle based calls
5998 since file handle passed in no longer valid */
5999
6000 return rc;
6001}
6002
6003int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006004CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006005 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006006 const struct cifs_unix_set_info_args *args,
6007 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008{
6009 TRANSACTION2_SPI_REQ *pSMB = NULL;
6010 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6011 int name_len;
6012 int rc = 0;
6013 int bytes_returned = 0;
6014 FILE_UNIX_BASIC_INFO *data_offset;
6015 __u16 params, param_offset, offset, count, byte_count;
6016
Joe Perchesf96637b2013-05-04 22:12:25 -05006017 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018setPermsRetry:
6019 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6020 (void **) &pSMBr);
6021 if (rc)
6022 return rc;
6023
6024 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6025 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006026 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006027 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 name_len++; /* trailing null */
6029 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006030 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006031 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006033 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034 }
6035
6036 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006037 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006039 /* BB find max SMB PDU from sess structure BB */
6040 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 pSMB->MaxSetupCount = 0;
6042 pSMB->Reserved = 0;
6043 pSMB->Flags = 0;
6044 pSMB->Timeout = 0;
6045 pSMB->Reserved2 = 0;
6046 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006047 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 offset = param_offset + params;
6049 data_offset =
6050 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6051 offset);
6052 memset(data_offset, 0, count);
6053 pSMB->DataOffset = cpu_to_le16(offset);
6054 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6055 pSMB->SetupCount = 1;
6056 pSMB->Reserved3 = 0;
6057 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6058 byte_count = 3 /* pad */ + params + count;
6059 pSMB->ParameterCount = cpu_to_le16(params);
6060 pSMB->DataCount = cpu_to_le16(count);
6061 pSMB->TotalParameterCount = pSMB->ParameterCount;
6062 pSMB->TotalDataCount = pSMB->DataCount;
6063 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6064 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006065 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006066
Jeff Layton654cf142009-07-09 20:02:49 -04006067 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068
6069 pSMB->ByteCount = cpu_to_le16(byte_count);
6070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006072 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006073 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074
Steve French0d817bc2008-05-22 02:02:03 +00006075 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 if (rc == -EAGAIN)
6077 goto setPermsRetry;
6078 return rc;
6079}
6080
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006082/*
6083 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6084 * function used by listxattr and getxattr type calls. When ea_name is set,
6085 * it looks for that attribute name and stuffs that value into the EAData
6086 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6087 * buffer. In both cases, the return value is either the length of the
6088 * resulting data or a negative error code. If EAData is a NULL pointer then
6089 * the data isn't copied to it, but the length is returned.
6090 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006092CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006093 const unsigned char *searchName, const unsigned char *ea_name,
6094 char *EAData, size_t buf_size,
6095 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096{
6097 /* BB assumes one setup word */
6098 TRANSACTION2_QPI_REQ *pSMB = NULL;
6099 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6100 int rc = 0;
6101 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006102 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006103 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006104 struct fea *temp_fea;
6105 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006106 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006107 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006108 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109
Joe Perchesf96637b2013-05-04 22:12:25 -05006110 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111QAllEAsRetry:
6112 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6113 (void **) &pSMBr);
6114 if (rc)
6115 return rc;
6116
6117 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006118 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006119 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6120 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006121 list_len++; /* trailing null */
6122 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006124 list_len = strnlen(searchName, PATH_MAX);
6125 list_len++; /* trailing null */
6126 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 }
6128
Jeff Layton6e462b92010-02-10 16:18:26 -05006129 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 pSMB->TotalDataCount = 0;
6131 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006132 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006133 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 pSMB->MaxSetupCount = 0;
6135 pSMB->Reserved = 0;
6136 pSMB->Flags = 0;
6137 pSMB->Timeout = 0;
6138 pSMB->Reserved2 = 0;
6139 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006140 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 pSMB->DataCount = 0;
6142 pSMB->DataOffset = 0;
6143 pSMB->SetupCount = 1;
6144 pSMB->Reserved3 = 0;
6145 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6146 byte_count = params + 1 /* pad */ ;
6147 pSMB->TotalParameterCount = cpu_to_le16(params);
6148 pSMB->ParameterCount = pSMB->TotalParameterCount;
6149 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6150 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006151 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 pSMB->ByteCount = cpu_to_le16(byte_count);
6153
6154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6155 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6156 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006157 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006158 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006160
6161
6162 /* BB also check enough total bytes returned */
6163 /* BB we need to improve the validity checking
6164 of these trans2 responses */
6165
6166 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006167 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006168 rc = -EIO; /* bad smb */
6169 goto QAllEAsOut;
6170 }
6171
6172 /* check that length of list is not more than bcc */
6173 /* check that each entry does not go beyond length
6174 of list */
6175 /* check that each element of each entry does not
6176 go beyond end of list */
6177 /* validate_trans2_offsets() */
6178 /* BB check if start of smb + data_offset > &bcc+ bcc */
6179
6180 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6181 ea_response_data = (struct fealist *)
6182 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6183
Jeff Layton6e462b92010-02-10 16:18:26 -05006184 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006185 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006186 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006187 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006188 /* didn't find the named attribute */
6189 if (ea_name)
6190 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006191 goto QAllEAsOut;
6192 }
6193
Jeff Layton0cd126b2010-02-10 16:18:26 -05006194 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006195 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006196 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006197 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006198 rc = -EIO;
6199 goto QAllEAsOut;
6200 }
6201
Jeff Laytonf0d38682010-02-10 16:18:26 -05006202 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006203 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006204 temp_fea = ea_response_data->list;
6205 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006206 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006207 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006208 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006209
Jeff Layton6e462b92010-02-10 16:18:26 -05006210 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006211 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006212 /* make sure we can read name_len and value_len */
6213 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006214 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006215 rc = -EIO;
6216 goto QAllEAsOut;
6217 }
6218
6219 name_len = temp_fea->name_len;
6220 value_len = le16_to_cpu(temp_fea->value_len);
6221 list_len -= name_len + 1 + value_len;
6222 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006223 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006224 rc = -EIO;
6225 goto QAllEAsOut;
6226 }
6227
Jeff Layton31c05192010-02-10 16:18:26 -05006228 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006229 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006230 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006231 temp_ptr += name_len + 1;
6232 rc = value_len;
6233 if (buf_size == 0)
6234 goto QAllEAsOut;
6235 if ((size_t)value_len > buf_size) {
6236 rc = -ERANGE;
6237 goto QAllEAsOut;
6238 }
6239 memcpy(EAData, temp_ptr, value_len);
6240 goto QAllEAsOut;
6241 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006242 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006243 /* account for prefix user. and trailing null */
6244 rc += (5 + 1 + name_len);
6245 if (rc < (int) buf_size) {
6246 memcpy(EAData, "user.", 5);
6247 EAData += 5;
6248 memcpy(EAData, temp_ptr, name_len);
6249 EAData += name_len;
6250 /* null terminate name */
6251 *EAData = 0;
6252 ++EAData;
6253 } else if (buf_size == 0) {
6254 /* skip copy - calc size only */
6255 } else {
6256 /* stop before overrun buffer */
6257 rc = -ERANGE;
6258 break;
6259 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006260 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006261 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006262 temp_fea = (struct fea *)temp_ptr;
6263 }
6264
Jeff Layton31c05192010-02-10 16:18:26 -05006265 /* didn't find the named attribute */
6266 if (ea_name)
6267 rc = -ENODATA;
6268
Jeff Laytonf0d38682010-02-10 16:18:26 -05006269QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006270 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 if (rc == -EAGAIN)
6272 goto QAllEAsRetry;
6273
6274 return (ssize_t)rc;
6275}
6276
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006278CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6279 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006280 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6281 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282{
6283 struct smb_com_transaction2_spi_req *pSMB = NULL;
6284 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6285 struct fealist *parm_data;
6286 int name_len;
6287 int rc = 0;
6288 int bytes_returned = 0;
6289 __u16 params, param_offset, byte_count, offset, count;
6290
Joe Perchesf96637b2013-05-04 22:12:25 -05006291 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292SetEARetry:
6293 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6294 (void **) &pSMBr);
6295 if (rc)
6296 return rc;
6297
6298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6299 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006300 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6301 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 name_len++; /* trailing null */
6303 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006304 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305 name_len = strnlen(fileName, PATH_MAX);
6306 name_len++; /* trailing null */
6307 strncpy(pSMB->FileName, fileName, name_len);
6308 }
6309
6310 params = 6 + name_len;
6311
6312 /* done calculating parms using name_len of file name,
6313 now use name_len to calculate length of ea name
6314 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006315 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 name_len = 0;
6317 else
Steve French50c2f752007-07-13 00:33:32 +00006318 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006320 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006322 /* BB find max SMB PDU from sess */
6323 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 pSMB->MaxSetupCount = 0;
6325 pSMB->Reserved = 0;
6326 pSMB->Flags = 0;
6327 pSMB->Timeout = 0;
6328 pSMB->Reserved2 = 0;
6329 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006330 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 offset = param_offset + params;
6332 pSMB->InformationLevel =
6333 cpu_to_le16(SMB_SET_FILE_EA);
6334
6335 parm_data =
6336 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6337 offset);
6338 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6339 pSMB->DataOffset = cpu_to_le16(offset);
6340 pSMB->SetupCount = 1;
6341 pSMB->Reserved3 = 0;
6342 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6343 byte_count = 3 /* pad */ + params + count;
6344 pSMB->DataCount = cpu_to_le16(count);
6345 parm_data->list_len = cpu_to_le32(count);
6346 parm_data->list[0].EA_flags = 0;
6347 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006348 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006350 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006351 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 parm_data->list[0].name[name_len] = 0;
6353 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6354 /* caller ensures that ea_value_len is less than 64K but
6355 we need to ensure that it fits within the smb */
6356
Steve French50c2f752007-07-13 00:33:32 +00006357 /*BB add length check to see if it would fit in
6358 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006359 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6360 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006361 memcpy(parm_data->list[0].name+name_len+1,
6362 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363
6364 pSMB->TotalDataCount = pSMB->DataCount;
6365 pSMB->ParameterCount = cpu_to_le16(params);
6366 pSMB->TotalParameterCount = pSMB->ParameterCount;
6367 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006368 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 pSMB->ByteCount = cpu_to_le16(byte_count);
6370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006372 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006373 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374
6375 cifs_buf_release(pSMB);
6376
6377 if (rc == -EAGAIN)
6378 goto SetEARetry;
6379
6380 return rc;
6381}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382#endif
Steve French0eff0e22011-02-24 05:39:23 +00006383
6384#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6385/*
6386 * Years ago the kernel added a "dnotify" function for Samba server,
6387 * to allow network clients (such as Windows) to display updated
6388 * lists of files in directory listings automatically when
6389 * files are added by one user when another user has the
6390 * same directory open on their desktop. The Linux cifs kernel
6391 * client hooked into the kernel side of this interface for
6392 * the same reason, but ironically when the VFS moved from
6393 * "dnotify" to "inotify" it became harder to plug in Linux
6394 * network file system clients (the most obvious use case
6395 * for notify interfaces is when multiple users can update
6396 * the contents of the same directory - exactly what network
6397 * file systems can do) although the server (Samba) could
6398 * still use it. For the short term we leave the worker
6399 * function ifdeffed out (below) until inotify is fixed
6400 * in the VFS to make it easier to plug in network file
6401 * system clients. If inotify turns out to be permanently
6402 * incompatible for network fs clients, we could instead simply
6403 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6404 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006405int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006406 const int notify_subdirs, const __u16 netfid,
6407 __u32 filter, struct file *pfile, int multishot,
6408 const struct nls_table *nls_codepage)
6409{
6410 int rc = 0;
6411 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6412 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6413 struct dir_notify_req *dnotify_req;
6414 int bytes_returned;
6415
Joe Perchesf96637b2013-05-04 22:12:25 -05006416 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006417 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6418 (void **) &pSMBr);
6419 if (rc)
6420 return rc;
6421
6422 pSMB->TotalParameterCount = 0 ;
6423 pSMB->TotalDataCount = 0;
6424 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006425 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006426 pSMB->MaxSetupCount = 4;
6427 pSMB->Reserved = 0;
6428 pSMB->ParameterOffset = 0;
6429 pSMB->DataCount = 0;
6430 pSMB->DataOffset = 0;
6431 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6432 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6433 pSMB->ParameterCount = pSMB->TotalParameterCount;
6434 if (notify_subdirs)
6435 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6436 pSMB->Reserved2 = 0;
6437 pSMB->CompletionFilter = cpu_to_le32(filter);
6438 pSMB->Fid = netfid; /* file handle always le */
6439 pSMB->ByteCount = 0;
6440
6441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6442 (struct smb_hdr *)pSMBr, &bytes_returned,
6443 CIFS_ASYNC_OP);
6444 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006445 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006446 } else {
6447 /* Add file to outstanding requests */
6448 /* BB change to kmem cache alloc */
6449 dnotify_req = kmalloc(
6450 sizeof(struct dir_notify_req),
6451 GFP_KERNEL);
6452 if (dnotify_req) {
6453 dnotify_req->Pid = pSMB->hdr.Pid;
6454 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6455 dnotify_req->Mid = pSMB->hdr.Mid;
6456 dnotify_req->Tid = pSMB->hdr.Tid;
6457 dnotify_req->Uid = pSMB->hdr.Uid;
6458 dnotify_req->netfid = netfid;
6459 dnotify_req->pfile = pfile;
6460 dnotify_req->filter = filter;
6461 dnotify_req->multishot = multishot;
6462 spin_lock(&GlobalMid_Lock);
6463 list_add_tail(&dnotify_req->lhead,
6464 &GlobalDnotifyReqList);
6465 spin_unlock(&GlobalMid_Lock);
6466 } else
6467 rc = -ENOMEM;
6468 }
6469 cifs_buf_release(pSMB);
6470 return rc;
6471}
6472#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */