blob: 4d881c35eecaa035717b52d9c19b9dac00dd9dae [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_lock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Jeff Layton44772882010-10-15 15:34:03 -0400107 spin_unlock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500142 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500166 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 rc = cifs_setup_session(0, ses, nls_codepage);
184
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 goto out;
189 }
190
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400191 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500194 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
199 /*
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
202 */
203 atomic_inc(&tconInfoReconnectCount);
204
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208
209 /*
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
212 *
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 */
215
216out:
217 /*
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
220 */
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
228 }
229
230 unload_nls(nls_codepage);
231 return rc;
232}
233
Steve Frenchad7a2922008-02-07 23:25:02 +0000234/* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int
Steve French96daf2b2011-05-27 04:34:02 +0000238small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000239 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Jeff Laytonf5695992010-09-29 15:27:08 -0400241 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000244 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return rc;
246
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
251 }
252
Steve French63135e02007-07-17 17:34:02 +0000253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000254 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Steve French790fe572007-07-07 19:25:05 +0000256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700258
Jeff Laytonf5695992010-09-29 15:27:08 -0400259 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000260}
261
Steve French12b3b8f2006-02-09 21:12:47 +0000262int
Steve French50c2f752007-07-13 00:33:32 +0000263small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000264 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000265{
266 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000267 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000268
Steve French5815449d2006-02-14 01:36:20 +0000269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 return rc;
272
Steve French04fdabe2006-02-10 05:52:50 +0000273 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400274 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000277 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279
280 /* uid, tid can stay at zero as set in header assemble */
281
Steve French50c2f752007-07-13 00:33:32 +0000282 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000283 this function is used after 1st of session setup requests */
284
285 return rc;
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288/* If the return code is zero, this function must fill in request_buf pointer */
289static int
Steve French96daf2b2011-05-27 04:34:02 +0000290__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400291 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700310
Jeff Laytonf5695992010-09-29 15:27:08 -0400311 return 0;
312}
313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
318{
319 int rc;
320
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
324
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326}
327
328static int
Steve French96daf2b2011-05-27 04:34:02 +0000329smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400330 void **request_buf, void **response_buf)
331{
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
334
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Steve French50c2f752007-07-13 00:33:32 +0000338static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
354
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
357 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
362
363 return 0;
364vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Jeff Layton690c5222011-01-20 13:36:51 -0500369
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400370static int
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) {
1737 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001738 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001739 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001740 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001741 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001742 /* return buffer to caller to free */
1743 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001744 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001745 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001746 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001747 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001748 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001749
1750 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 since file handle passed in no longer valid */
1752 return rc;
1753}
1754
Steve Frenchec637e32005-12-12 20:53:18 -08001755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001757CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001758 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001759 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760{
1761 int rc = -EACCES;
1762 WRITE_REQ *pSMB = NULL;
1763 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001764 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 __u32 bytes_sent;
1766 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001767 __u32 pid = io_parms->pid;
1768 __u16 netfid = io_parms->netfid;
1769 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001770 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001771 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
Steve Frencha24e2d72010-04-03 17:20:21 +00001773 *nbytes = 0;
1774
Joe Perchesf96637b2013-05-04 22:12:25 -05001775 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001776 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001777 return -ECONNABORTED;
1778
Steve French790fe572007-07-07 19:25:05 +00001779 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001780 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001781 else {
Steve French1c955182005-08-30 20:58:07 -07001782 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001783 if ((offset >> 32) > 0) {
1784 /* can not handle big offset for old srv */
1785 return -EIO;
1786 }
1787 }
Steve French1c955182005-08-30 20:58:07 -07001788
1789 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 (void **) &pSMBr);
1791 if (rc)
1792 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001793
1794 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1795 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1796
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 /* tcon and ses pointer are checked in smb_init */
1798 if (tcon->ses->server == NULL)
1799 return -ECONNABORTED;
1800
1801 pSMB->AndXCommand = 0xFF; /* none */
1802 pSMB->Fid = netfid;
1803 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001804 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001805 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 pSMB->Reserved = 0xFFFFFFFF;
1808 pSMB->WriteMode = 0;
1809 pSMB->Remaining = 0;
1810
Steve French50c2f752007-07-13 00:33:32 +00001811 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 can send more if LARGE_WRITE_X capability returned by the server and if
1813 our buffer is big enough or if we convert to iovecs on socket writes
1814 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001815 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1817 } else {
1818 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1819 & ~0xFF;
1820 }
1821
1822 if (bytes_sent > count)
1823 bytes_sent = count;
1824 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001825 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001826 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001827 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001828 else if (ubuf) {
1829 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 cifs_buf_release(pSMB);
1831 return -EFAULT;
1832 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001833 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 /* No buffer */
1835 cifs_buf_release(pSMB);
1836 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001837 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001838 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001839 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001840 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001841 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1844 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001845 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001846
Steve French790fe572007-07-07 19:25:05 +00001847 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001848 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001849 else { /* old style write has byte count 4 bytes earlier
1850 so 4 bytes pad */
1851 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001852 (struct smb_com_writex_req *)pSMB;
1853 pSMBW->ByteCount = cpu_to_le16(byte_count);
1854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
1856 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1857 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001858 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001860 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 } else {
1862 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1863 *nbytes = (*nbytes) << 16;
1864 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301865
1866 /*
1867 * Mask off high 16 bits when bytes written as returned by the
1868 * server is greater than bytes requested by the client. Some
1869 * OS/2 servers are known to set incorrect CountHigh values.
1870 */
1871 if (*nbytes > count)
1872 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 }
1874
1875 cifs_buf_release(pSMB);
1876
Steve French50c2f752007-07-13 00:33:32 +00001877 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 since file handle passed in no longer valid */
1879
1880 return rc;
1881}
1882
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001883void
1884cifs_writedata_release(struct kref *refcount)
1885{
1886 struct cifs_writedata *wdata = container_of(refcount,
1887 struct cifs_writedata, refcount);
1888
1889 if (wdata->cfile)
1890 cifsFileInfo_put(wdata->cfile);
1891
1892 kfree(wdata);
1893}
1894
1895/*
1896 * Write failed with a retryable error. Resend the write request. It's also
1897 * possible that the page was redirtied so re-clean the page.
1898 */
1899static void
1900cifs_writev_requeue(struct cifs_writedata *wdata)
1901{
1902 int i, rc;
1903 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001904 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001905
1906 for (i = 0; i < wdata->nr_pages; i++) {
1907 lock_page(wdata->pages[i]);
1908 clear_page_dirty_for_io(wdata->pages[i]);
1909 }
1910
1911 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001912 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1913 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001914 } while (rc == -EAGAIN);
1915
1916 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001917 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001918 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001919 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001920 end_page_writeback(wdata->pages[i]);
1921 page_cache_release(wdata->pages[i]);
1922 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001923 }
1924
1925 mapping_set_error(inode->i_mapping, rc);
1926 kref_put(&wdata->refcount, cifs_writedata_release);
1927}
1928
Jeff Laytonc2e87642012-03-23 14:40:55 -04001929void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001930cifs_writev_complete(struct work_struct *work)
1931{
1932 struct cifs_writedata *wdata = container_of(work,
1933 struct cifs_writedata, work);
1934 struct inode *inode = wdata->cfile->dentry->d_inode;
1935 int i = 0;
1936
1937 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001938 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001939 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001940 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001941 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1942 wdata->bytes);
1943 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1944 return cifs_writev_requeue(wdata);
1945
1946 for (i = 0; i < wdata->nr_pages; i++) {
1947 struct page *page = wdata->pages[i];
1948 if (wdata->result == -EAGAIN)
1949 __set_page_dirty_nobuffers(page);
1950 else if (wdata->result < 0)
1951 SetPageError(page);
1952 end_page_writeback(page);
1953 page_cache_release(page);
1954 }
1955 if (wdata->result != -EAGAIN)
1956 mapping_set_error(inode->i_mapping, wdata->result);
1957 kref_put(&wdata->refcount, cifs_writedata_release);
1958}
1959
1960struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001961cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001962{
1963 struct cifs_writedata *wdata;
1964
1965 /* this would overflow */
1966 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001967 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001968 return NULL;
1969 }
1970
1971 /* writedata + number of page pointers */
1972 wdata = kzalloc(sizeof(*wdata) +
1973 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1974 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001975 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001976 INIT_LIST_HEAD(&wdata->list);
1977 init_completion(&wdata->done);
1978 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001979 }
1980 return wdata;
1981}
1982
1983/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001984 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001985 * workqueue completion task.
1986 */
1987static void
1988cifs_writev_callback(struct mid_q_entry *mid)
1989{
1990 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001991 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001992 unsigned int written;
1993 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1994
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001995 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001996 case MID_RESPONSE_RECEIVED:
1997 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1998 if (wdata->result != 0)
1999 break;
2000
2001 written = le16_to_cpu(smb->CountHigh);
2002 written <<= 16;
2003 written += le16_to_cpu(smb->Count);
2004 /*
2005 * Mask off high 16 bits when bytes written as returned
2006 * by the server is greater than bytes requested by the
2007 * client. OS/2 servers are known to set incorrect
2008 * CountHigh values.
2009 */
2010 if (written > wdata->bytes)
2011 written &= 0xFFFF;
2012
2013 if (written < wdata->bytes)
2014 wdata->result = -ENOSPC;
2015 else
2016 wdata->bytes = written;
2017 break;
2018 case MID_REQUEST_SUBMITTED:
2019 case MID_RETRY_NEEDED:
2020 wdata->result = -EAGAIN;
2021 break;
2022 default:
2023 wdata->result = -EIO;
2024 break;
2025 }
2026
Jeff Laytonda472fc2012-03-23 14:40:53 -04002027 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002028 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002029 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002030}
2031
2032/* cifs_async_writev - send an async write, and set up mid to handle result */
2033int
2034cifs_async_writev(struct cifs_writedata *wdata)
2035{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002036 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002037 WRITE_REQ *smb = NULL;
2038 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002039 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002040 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002041 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002042
2043 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2044 wct = 14;
2045 } else {
2046 wct = 12;
2047 if (wdata->offset >> 32 > 0) {
2048 /* can not handle big offset for old srv */
2049 return -EIO;
2050 }
2051 }
2052
2053 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2054 if (rc)
2055 goto async_writev_out;
2056
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002057 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2058 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002059
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002060 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002061 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2063 if (wct == 14)
2064 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2065 smb->Reserved = 0xFFFFFFFF;
2066 smb->WriteMode = 0;
2067 smb->Remaining = 0;
2068
2069 smb->DataOffset =
2070 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2071
2072 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002073 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2074 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002075
Jeff Laytoneddb0792012-09-18 16:20:35 -07002076 rqst.rq_iov = &iov;
2077 rqst.rq_nvec = 1;
2078 rqst.rq_pages = wdata->pages;
2079 rqst.rq_npages = wdata->nr_pages;
2080 rqst.rq_pagesz = wdata->pagesz;
2081 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082
Joe Perchesf96637b2013-05-04 22:12:25 -05002083 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2084 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002085
2086 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2087 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2088
2089 if (wct == 14) {
2090 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2091 put_bcc(wdata->bytes + 1, &smb->hdr);
2092 } else {
2093 /* wct == 12 */
2094 struct smb_com_writex_req *smbw =
2095 (struct smb_com_writex_req *)smb;
2096 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2097 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002098 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099 }
2100
2101 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002102 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2103 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002104
2105 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002106 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002107 else
2108 kref_put(&wdata->refcount, cifs_writedata_release);
2109
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002110async_writev_out:
2111 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002112 return rc;
2113}
2114
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002115int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002116CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002117 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118{
2119 int rc = -EACCES;
2120 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002121 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002122 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002123 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002124 __u32 pid = io_parms->pid;
2125 __u16 netfid = io_parms->netfid;
2126 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002127 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002128 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002130 *nbytes = 0;
2131
Joe Perchesf96637b2013-05-04 22:12:25 -05002132 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002133
Steve French4c3130e2008-12-09 00:28:16 +00002134 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002135 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002136 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002137 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002138 if ((offset >> 32) > 0) {
2139 /* can not handle big offset for old srv */
2140 return -EIO;
2141 }
2142 }
Steve French8cc64c62005-10-03 13:49:43 -07002143 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 if (rc)
2145 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002146
2147 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2148 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 /* tcon and ses pointer are checked in smb_init */
2151 if (tcon->ses->server == NULL)
2152 return -ECONNABORTED;
2153
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002154 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 pSMB->Fid = netfid;
2156 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002157 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002158 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 pSMB->Reserved = 0xFFFFFFFF;
2160 pSMB->WriteMode = 0;
2161 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002162
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002164 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
Steve French3e844692005-10-03 13:37:24 -07002166 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2167 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002168 /* header + 1 byte pad */
2169 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002170 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002171 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002172 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002173 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002174 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002175 pSMB->ByteCount = cpu_to_le16(count + 1);
2176 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002177 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002178 (struct smb_com_writex_req *)pSMB;
2179 pSMBW->ByteCount = cpu_to_le16(count + 5);
2180 }
Steve French3e844692005-10-03 13:37:24 -07002181 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002182 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002183 iov[0].iov_len = smb_hdr_len + 4;
2184 else /* wct == 12 pad bigger by four bytes */
2185 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002186
Steve French3e844692005-10-03 13:37:24 -07002187
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002188 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002189 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002191 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002192 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002193 /* presumably this can not happen, but best to be safe */
2194 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002195 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002196 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002197 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2198 *nbytes = (*nbytes) << 16;
2199 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302200
2201 /*
2202 * Mask off high 16 bits when bytes written as returned by the
2203 * server is greater than bytes requested by the client. OS/2
2204 * servers are known to set incorrect CountHigh values.
2205 */
2206 if (*nbytes > count)
2207 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Steve French4b8f9302006-02-26 16:41:18 +00002210/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002211 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002212 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002213 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002214 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Steve French50c2f752007-07-13 00:33:32 +00002216 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 since file handle passed in no longer valid */
2218
2219 return rc;
2220}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002221
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002222int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2223 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002224 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2225{
2226 int rc = 0;
2227 LOCK_REQ *pSMB = NULL;
2228 struct kvec iov[2];
2229 int resp_buf_type;
2230 __u16 count;
2231
Joe Perchesf96637b2013-05-04 22:12:25 -05002232 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2233 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002234
2235 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2236 if (rc)
2237 return rc;
2238
2239 pSMB->Timeout = 0;
2240 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2241 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2242 pSMB->LockType = lock_type;
2243 pSMB->AndXCommand = 0xFF; /* none */
2244 pSMB->Fid = netfid; /* netfid stays le */
2245
2246 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2247 inc_rfc1001_len(pSMB, count);
2248 pSMB->ByteCount = cpu_to_le16(count);
2249
2250 iov[0].iov_base = (char *)pSMB;
2251 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2252 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2253 iov[1].iov_base = (char *)buf;
2254 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2255
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002256 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002257 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2258 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002259 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002260
2261 return rc;
2262}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002263
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002265CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002266 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002268 const __u32 numLock, const __u8 lockType,
2269 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270{
2271 int rc = 0;
2272 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002273/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002275 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 __u16 count;
2277
Joe Perchesf96637b2013-05-04 22:12:25 -05002278 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2279 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002280 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2281
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 if (rc)
2283 return rc;
2284
Steve French790fe572007-07-07 19:25:05 +00002285 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002286 /* no response expected */
2287 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002289 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002290 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2292 } else {
2293 pSMB->Timeout = 0;
2294 }
2295
2296 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2297 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2298 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002299 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 pSMB->AndXCommand = 0xFF; /* none */
2301 pSMB->Fid = smb_file_id; /* netfid stays le */
2302
Steve French790fe572007-07-07 19:25:05 +00002303 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002304 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 /* BB where to store pid high? */
2306 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2307 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2308 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2309 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2310 count = sizeof(LOCKING_ANDX_RANGE);
2311 } else {
2312 /* oplock break */
2313 count = 0;
2314 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002315 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 pSMB->ByteCount = cpu_to_le16(count);
2317
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002318 if (waitFlag) {
2319 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002320 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002321 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002322 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002323 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002324 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002325 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002326 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002327 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002328 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Steve French50c2f752007-07-13 00:33:32 +00002330 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 since file handle passed in no longer valid */
2332 return rc;
2333}
2334
2335int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002336CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002337 const __u16 smb_file_id, const __u32 netpid,
2338 const loff_t start_offset, const __u64 len,
2339 struct file_lock *pLockData, const __u16 lock_type,
2340 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002341{
2342 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2343 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002344 struct cifs_posix_lock *parm_data;
2345 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002346 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002347 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002348 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002349 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002350 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002351
Joe Perchesf96637b2013-05-04 22:12:25 -05002352 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002353
Steve French08547b02006-02-28 22:39:25 +00002354 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2355
2356 if (rc)
2357 return rc;
2358
2359 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2360
Steve French50c2f752007-07-13 00:33:32 +00002361 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002362 pSMB->MaxSetupCount = 0;
2363 pSMB->Reserved = 0;
2364 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002365 pSMB->Reserved2 = 0;
2366 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2367 offset = param_offset + params;
2368
Steve French08547b02006-02-28 22:39:25 +00002369 count = sizeof(struct cifs_posix_lock);
2370 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002371 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002372 pSMB->SetupCount = 1;
2373 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002374 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002375 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2376 else
2377 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2378 byte_count = 3 /* pad */ + params + count;
2379 pSMB->DataCount = cpu_to_le16(count);
2380 pSMB->ParameterCount = cpu_to_le16(params);
2381 pSMB->TotalDataCount = pSMB->DataCount;
2382 pSMB->TotalParameterCount = pSMB->ParameterCount;
2383 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002384 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002385 (((char *) &pSMB->hdr.Protocol) + offset);
2386
2387 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002388 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002389 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002390 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002391 pSMB->Timeout = cpu_to_le32(-1);
2392 } else
2393 pSMB->Timeout = 0;
2394
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002395 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002396 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002397 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002398
2399 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002400 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002401 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2402 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002403 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002404 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002405 if (waitFlag) {
2406 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2407 (struct smb_hdr *) pSMBr, &bytes_returned);
2408 } else {
Steve French133672e2007-11-13 22:41:37 +00002409 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002410 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002411 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2412 &resp_buf_type, timeout);
2413 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2414 not try to free it twice below on exit */
2415 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002416 }
2417
Steve French08547b02006-02-28 22:39:25 +00002418 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002419 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002420 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002421 /* lock structure can be returned on get */
2422 __u16 data_offset;
2423 __u16 data_count;
2424 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002425
Jeff Layton820a8032011-05-04 08:05:26 -04002426 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002427 rc = -EIO; /* bad smb */
2428 goto plk_err_exit;
2429 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002430 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2431 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002432 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002433 rc = -EIO;
2434 goto plk_err_exit;
2435 }
2436 parm_data = (struct cifs_posix_lock *)
2437 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002438 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002439 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002440 else {
2441 if (parm_data->lock_type ==
2442 __constant_cpu_to_le16(CIFS_RDLCK))
2443 pLockData->fl_type = F_RDLCK;
2444 else if (parm_data->lock_type ==
2445 __constant_cpu_to_le16(CIFS_WRLCK))
2446 pLockData->fl_type = F_WRLCK;
2447
Steve French5443d132011-03-13 05:08:25 +00002448 pLockData->fl_start = le64_to_cpu(parm_data->start);
2449 pLockData->fl_end = pLockData->fl_start +
2450 le64_to_cpu(parm_data->length) - 1;
2451 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002452 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002453 }
Steve French50c2f752007-07-13 00:33:32 +00002454
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002455plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002456 if (pSMB)
2457 cifs_small_buf_release(pSMB);
2458
Steve French133672e2007-11-13 22:41:37 +00002459 if (resp_buf_type == CIFS_SMALL_BUFFER)
2460 cifs_small_buf_release(iov[0].iov_base);
2461 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2462 cifs_buf_release(iov[0].iov_base);
2463
Steve French08547b02006-02-28 22:39:25 +00002464 /* Note: On -EAGAIN error only caller can retry on handle based calls
2465 since file handle passed in no longer valid */
2466
2467 return rc;
2468}
2469
2470
2471int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002472CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473{
2474 int rc = 0;
2475 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002476 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
2478/* do not retry on dead session on close */
2479 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002480 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 return 0;
2482 if (rc)
2483 return rc;
2484
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002486 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002488 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002489 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002491 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002493 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 }
2495 }
2496
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002498 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 rc = 0;
2500
2501 return rc;
2502}
2503
2504int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002505CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002506{
2507 int rc = 0;
2508 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002509 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002510
2511 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2512 if (rc)
2513 return rc;
2514
2515 pSMB->FileID = (__u16) smb_file_id;
2516 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002517 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002518 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002519 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002520 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002521
2522 return rc;
2523}
2524
2525int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002526CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002527 const char *from_name, const char *to_name,
2528 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529{
2530 int rc = 0;
2531 RENAME_REQ *pSMB = NULL;
2532 RENAME_RSP *pSMBr = NULL;
2533 int bytes_returned;
2534 int name_len, name_len2;
2535 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002536 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Joe Perchesf96637b2013-05-04 22:12:25 -05002538 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539renameRetry:
2540 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2541 (void **) &pSMBr);
2542 if (rc)
2543 return rc;
2544
2545 pSMB->BufferFormat = 0x04;
2546 pSMB->SearchAttributes =
2547 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2548 ATTR_DIRECTORY);
2549
2550 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002551 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2552 from_name, PATH_MAX,
2553 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 name_len++; /* trailing null */
2555 name_len *= 2;
2556 pSMB->OldFileName[name_len] = 0x04; /* pad */
2557 /* protocol requires ASCII signature byte on Unicode string */
2558 pSMB->OldFileName[name_len + 1] = 0x00;
2559 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002560 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002561 to_name, PATH_MAX, cifs_sb->local_nls,
2562 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2564 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002565 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002566 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002568 strncpy(pSMB->OldFileName, from_name, name_len);
2569 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 name_len2++; /* trailing null */
2571 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002572 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 name_len2++; /* trailing null */
2574 name_len2++; /* signature byte */
2575 }
2576
2577 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002578 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 pSMB->ByteCount = cpu_to_le16(count);
2580
2581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2582 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002583 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002584 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002585 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 cifs_buf_release(pSMB);
2588
2589 if (rc == -EAGAIN)
2590 goto renameRetry;
2591
2592 return rc;
2593}
2594
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002595int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002596 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002597 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598{
2599 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2600 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002601 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 char *data_offset;
2603 char dummy_string[30];
2604 int rc = 0;
2605 int bytes_returned = 0;
2606 int len_of_str;
2607 __u16 params, param_offset, offset, count, byte_count;
2608
Joe Perchesf96637b2013-05-04 22:12:25 -05002609 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2611 (void **) &pSMBr);
2612 if (rc)
2613 return rc;
2614
2615 params = 6;
2616 pSMB->MaxSetupCount = 0;
2617 pSMB->Reserved = 0;
2618 pSMB->Flags = 0;
2619 pSMB->Timeout = 0;
2620 pSMB->Reserved2 = 0;
2621 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2622 offset = param_offset + params;
2623
2624 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2625 rename_info = (struct set_file_rename *) data_offset;
2626 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002627 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 pSMB->SetupCount = 1;
2629 pSMB->Reserved3 = 0;
2630 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2631 byte_count = 3 /* pad */ + params;
2632 pSMB->ParameterCount = cpu_to_le16(params);
2633 pSMB->TotalParameterCount = pSMB->ParameterCount;
2634 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2635 pSMB->DataOffset = cpu_to_le16(offset);
2636 /* construct random name ".cifs_tmp<inodenum><mid>" */
2637 rename_info->overwrite = cpu_to_le32(1);
2638 rename_info->root_fid = 0;
2639 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002640 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002641 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002642 len_of_str =
2643 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002644 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002646 len_of_str =
2647 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002648 target_name, PATH_MAX, nls_codepage,
2649 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 }
2651 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002652 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 byte_count += count;
2654 pSMB->DataCount = cpu_to_le16(count);
2655 pSMB->TotalDataCount = pSMB->DataCount;
2656 pSMB->Fid = netfid;
2657 pSMB->InformationLevel =
2658 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2659 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002660 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 pSMB->ByteCount = cpu_to_le16(byte_count);
2662 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002663 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002664 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002665 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002666 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2667 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 cifs_buf_release(pSMB);
2670
2671 /* Note: On -EAGAIN error only caller can retry on handle based calls
2672 since file handle passed in no longer valid */
2673
2674 return rc;
2675}
2676
2677int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002678CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2679 const char *fromName, const __u16 target_tid, const char *toName,
2680 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
2682 int rc = 0;
2683 COPY_REQ *pSMB = NULL;
2684 COPY_RSP *pSMBr = NULL;
2685 int bytes_returned;
2686 int name_len, name_len2;
2687 __u16 count;
2688
Joe Perchesf96637b2013-05-04 22:12:25 -05002689 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690copyRetry:
2691 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2692 (void **) &pSMBr);
2693 if (rc)
2694 return rc;
2695
2696 pSMB->BufferFormat = 0x04;
2697 pSMB->Tid2 = target_tid;
2698
2699 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2700
2701 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002702 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2703 fromName, PATH_MAX, nls_codepage,
2704 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 name_len++; /* trailing null */
2706 name_len *= 2;
2707 pSMB->OldFileName[name_len] = 0x04; /* pad */
2708 /* protocol requires ASCII signature byte on Unicode string */
2709 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002710 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002711 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2712 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2714 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002715 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 name_len = strnlen(fromName, PATH_MAX);
2717 name_len++; /* trailing null */
2718 strncpy(pSMB->OldFileName, fromName, name_len);
2719 name_len2 = strnlen(toName, PATH_MAX);
2720 name_len2++; /* trailing null */
2721 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2722 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2723 name_len2++; /* trailing null */
2724 name_len2++; /* signature byte */
2725 }
2726
2727 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002728 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 pSMB->ByteCount = cpu_to_le16(count);
2730
2731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2733 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002734 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2735 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 }
Steve French0d817bc2008-05-22 02:02:03 +00002737 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
2739 if (rc == -EAGAIN)
2740 goto copyRetry;
2741
2742 return rc;
2743}
2744
2745int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002746CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 const char *fromName, const char *toName,
2748 const struct nls_table *nls_codepage)
2749{
2750 TRANSACTION2_SPI_REQ *pSMB = NULL;
2751 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2752 char *data_offset;
2753 int name_len;
2754 int name_len_target;
2755 int rc = 0;
2756 int bytes_returned = 0;
2757 __u16 params, param_offset, offset, byte_count;
2758
Joe Perchesf96637b2013-05-04 22:12:25 -05002759 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760createSymLinkRetry:
2761 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2762 (void **) &pSMBr);
2763 if (rc)
2764 return rc;
2765
2766 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2767 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002768 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2769 /* find define for this maxpathcomponent */
2770 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 name_len++; /* trailing null */
2772 name_len *= 2;
2773
Steve French50c2f752007-07-13 00:33:32 +00002774 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 name_len = strnlen(fromName, PATH_MAX);
2776 name_len++; /* trailing null */
2777 strncpy(pSMB->FileName, fromName, name_len);
2778 }
2779 params = 6 + name_len;
2780 pSMB->MaxSetupCount = 0;
2781 pSMB->Reserved = 0;
2782 pSMB->Flags = 0;
2783 pSMB->Timeout = 0;
2784 pSMB->Reserved2 = 0;
2785 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002786 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 offset = param_offset + params;
2788
2789 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2791 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002792 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2793 /* find define for this maxpathcomponent */
2794 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 name_len_target++; /* trailing null */
2796 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002797 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 name_len_target = strnlen(toName, PATH_MAX);
2799 name_len_target++; /* trailing null */
2800 strncpy(data_offset, toName, name_len_target);
2801 }
2802
2803 pSMB->MaxParameterCount = cpu_to_le16(2);
2804 /* BB find exact max on data count below from sess */
2805 pSMB->MaxDataCount = cpu_to_le16(1000);
2806 pSMB->SetupCount = 1;
2807 pSMB->Reserved3 = 0;
2808 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2809 byte_count = 3 /* pad */ + params + name_len_target;
2810 pSMB->DataCount = cpu_to_le16(name_len_target);
2811 pSMB->ParameterCount = cpu_to_le16(params);
2812 pSMB->TotalDataCount = pSMB->DataCount;
2813 pSMB->TotalParameterCount = pSMB->ParameterCount;
2814 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2815 pSMB->DataOffset = cpu_to_le16(offset);
2816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2817 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002818 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 pSMB->ByteCount = cpu_to_le16(byte_count);
2820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002822 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002823 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002824 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2825 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
Steve French0d817bc2008-05-22 02:02:03 +00002827 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828
2829 if (rc == -EAGAIN)
2830 goto createSymLinkRetry;
2831
2832 return rc;
2833}
2834
2835int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002836CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002838 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839{
2840 TRANSACTION2_SPI_REQ *pSMB = NULL;
2841 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2842 char *data_offset;
2843 int name_len;
2844 int name_len_target;
2845 int rc = 0;
2846 int bytes_returned = 0;
2847 __u16 params, param_offset, offset, byte_count;
2848
Joe Perchesf96637b2013-05-04 22:12:25 -05002849 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850createHardLinkRetry:
2851 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2852 (void **) &pSMBr);
2853 if (rc)
2854 return rc;
2855
2856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002857 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2858 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 name_len++; /* trailing null */
2860 name_len *= 2;
2861
Steve French50c2f752007-07-13 00:33:32 +00002862 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 name_len = strnlen(toName, PATH_MAX);
2864 name_len++; /* trailing null */
2865 strncpy(pSMB->FileName, toName, name_len);
2866 }
2867 params = 6 + name_len;
2868 pSMB->MaxSetupCount = 0;
2869 pSMB->Reserved = 0;
2870 pSMB->Flags = 0;
2871 pSMB->Timeout = 0;
2872 pSMB->Reserved2 = 0;
2873 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002874 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 offset = param_offset + params;
2876
2877 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2878 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2879 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002880 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2881 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 name_len_target++; /* trailing null */
2883 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002884 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 name_len_target = strnlen(fromName, PATH_MAX);
2886 name_len_target++; /* trailing null */
2887 strncpy(data_offset, fromName, name_len_target);
2888 }
2889
2890 pSMB->MaxParameterCount = cpu_to_le16(2);
2891 /* BB find exact max on data count below from sess*/
2892 pSMB->MaxDataCount = cpu_to_le16(1000);
2893 pSMB->SetupCount = 1;
2894 pSMB->Reserved3 = 0;
2895 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2896 byte_count = 3 /* pad */ + params + name_len_target;
2897 pSMB->ParameterCount = cpu_to_le16(params);
2898 pSMB->TotalParameterCount = pSMB->ParameterCount;
2899 pSMB->DataCount = cpu_to_le16(name_len_target);
2900 pSMB->TotalDataCount = pSMB->DataCount;
2901 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2902 pSMB->DataOffset = cpu_to_le16(offset);
2903 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2904 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002905 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 pSMB->ByteCount = cpu_to_le16(byte_count);
2907 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2908 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002909 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002910 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002911 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2912 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913
2914 cifs_buf_release(pSMB);
2915 if (rc == -EAGAIN)
2916 goto createHardLinkRetry;
2917
2918 return rc;
2919}
2920
2921int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002922CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002923 const char *from_name, const char *to_name,
2924 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925{
2926 int rc = 0;
2927 NT_RENAME_REQ *pSMB = NULL;
2928 RENAME_RSP *pSMBr = NULL;
2929 int bytes_returned;
2930 int name_len, name_len2;
2931 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002932 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
Joe Perchesf96637b2013-05-04 22:12:25 -05002934 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935winCreateHardLinkRetry:
2936
2937 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2938 (void **) &pSMBr);
2939 if (rc)
2940 return rc;
2941
2942 pSMB->SearchAttributes =
2943 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2944 ATTR_DIRECTORY);
2945 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2946 pSMB->ClusterCount = 0;
2947
2948 pSMB->BufferFormat = 0x04;
2949
2950 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2951 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002952 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2953 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 name_len++; /* trailing null */
2955 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002956
2957 /* protocol specifies ASCII buffer format (0x04) for unicode */
2958 pSMB->OldFileName[name_len] = 0x04;
2959 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002961 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002962 to_name, PATH_MAX, cifs_sb->local_nls,
2963 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2965 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002966 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002967 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002969 strncpy(pSMB->OldFileName, from_name, name_len);
2970 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 name_len2++; /* trailing null */
2972 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002973 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 name_len2++; /* trailing null */
2975 name_len2++; /* signature byte */
2976 }
2977
2978 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002979 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 pSMB->ByteCount = cpu_to_le16(count);
2981
2982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002984 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002985 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002986 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002987
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 cifs_buf_release(pSMB);
2989 if (rc == -EAGAIN)
2990 goto winCreateHardLinkRetry;
2991
2992 return rc;
2993}
2994
2995int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002996CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002997 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 const struct nls_table *nls_codepage)
2999{
3000/* SMB_QUERY_FILE_UNIX_LINK */
3001 TRANSACTION2_QPI_REQ *pSMB = NULL;
3002 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3003 int rc = 0;
3004 int bytes_returned;
3005 int name_len;
3006 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003007 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
Joe Perchesf96637b2013-05-04 22:12:25 -05003009 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
3011querySymLinkRetry:
3012 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3013 (void **) &pSMBr);
3014 if (rc)
3015 return rc;
3016
3017 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3018 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003019 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3020 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 name_len++; /* trailing null */
3022 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003023 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 name_len = strnlen(searchName, PATH_MAX);
3025 name_len++; /* trailing null */
3026 strncpy(pSMB->FileName, searchName, name_len);
3027 }
3028
3029 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3030 pSMB->TotalDataCount = 0;
3031 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003032 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 pSMB->MaxSetupCount = 0;
3034 pSMB->Reserved = 0;
3035 pSMB->Flags = 0;
3036 pSMB->Timeout = 0;
3037 pSMB->Reserved2 = 0;
3038 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003039 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 pSMB->DataCount = 0;
3041 pSMB->DataOffset = 0;
3042 pSMB->SetupCount = 1;
3043 pSMB->Reserved3 = 0;
3044 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3045 byte_count = params + 1 /* pad */ ;
3046 pSMB->TotalParameterCount = cpu_to_le16(params);
3047 pSMB->ParameterCount = pSMB->TotalParameterCount;
3048 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3049 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003050 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pSMB->ByteCount = cpu_to_le16(byte_count);
3052
3053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3055 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003056 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 } else {
3058 /* decode response */
3059
3060 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003062 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003063 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003065 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003066 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
Jeff Layton460b9692009-04-30 07:17:56 -04003068 data_start = ((char *) &pSMBr->hdr.Protocol) +
3069 le16_to_cpu(pSMBr->t2.DataOffset);
3070
Steve French0e0d2cf2009-05-01 05:27:32 +00003071 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3072 is_unicode = true;
3073 else
3074 is_unicode = false;
3075
Steve French737b7582005-04-28 22:41:06 -07003076 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003077 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3078 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003079 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003080 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 }
3082 }
3083 cifs_buf_release(pSMB);
3084 if (rc == -EAGAIN)
3085 goto querySymLinkRetry;
3086 return rc;
3087}
3088
Steve Frenchc52a9552011-02-24 06:16:22 +00003089/*
3090 * Recent Windows versions now create symlinks more frequently
3091 * and they use the "reparse point" mechanism below. We can of course
3092 * do symlinks nicely to Samba and other servers which support the
3093 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3094 * "MF" symlinks optionally, but for recent Windows we really need to
3095 * reenable the code below and fix the cifs_symlink callers to handle this.
3096 * In the interim this code has been moved to its own config option so
3097 * it is not compiled in by default until callers fixed up and more tested.
3098 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003100CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3101 __u16 fid, char **symlinkinfo,
3102 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103{
3104 int rc = 0;
3105 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003106 struct smb_com_transaction_ioctl_req *pSMB;
3107 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003108 bool is_unicode;
3109 unsigned int sub_len;
3110 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003111 struct reparse_symlink_data *reparse_buf;
3112 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003113 __u32 data_offset, data_count;
3114 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003116 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3118 (void **) &pSMBr);
3119 if (rc)
3120 return rc;
3121
3122 pSMB->TotalParameterCount = 0 ;
3123 pSMB->TotalDataCount = 0;
3124 pSMB->MaxParameterCount = cpu_to_le32(2);
3125 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003126 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 pSMB->MaxSetupCount = 4;
3128 pSMB->Reserved = 0;
3129 pSMB->ParameterOffset = 0;
3130 pSMB->DataCount = 0;
3131 pSMB->DataOffset = 0;
3132 pSMB->SetupCount = 4;
3133 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3134 pSMB->ParameterCount = pSMB->TotalParameterCount;
3135 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3136 pSMB->IsFsctl = 1; /* FSCTL */
3137 pSMB->IsRootFlag = 0;
3138 pSMB->Fid = fid; /* file handle always le */
3139 pSMB->ByteCount = 0;
3140
3141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3143 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003144 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003145 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 }
Steve French989c7e52009-05-02 05:32:20 +00003147
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003148 data_offset = le32_to_cpu(pSMBr->DataOffset);
3149 data_count = le32_to_cpu(pSMBr->DataCount);
3150 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3151 /* BB also check enough total bytes returned */
3152 rc = -EIO; /* bad smb */
3153 goto qreparse_out;
3154 }
3155 if (!data_count || (data_count > 2048)) {
3156 rc = -EIO;
3157 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3158 goto qreparse_out;
3159 }
3160 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003161 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003162 ((char *)&pSMBr->hdr.Protocol + data_offset);
3163 if ((char *)reparse_buf >= end_of_smb) {
3164 rc = -EIO;
3165 goto qreparse_out;
3166 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003167 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3168 cifs_dbg(FYI, "NFS style reparse tag\n");
3169 posix_buf = (struct reparse_posix_data *)reparse_buf;
3170
3171 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3172 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3173 le64_to_cpu(posix_buf->InodeType));
3174 rc = -EOPNOTSUPP;
3175 goto qreparse_out;
3176 }
3177 is_unicode = true;
3178 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3179 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3180 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3181 rc = -EIO;
3182 goto qreparse_out;
3183 }
3184 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3185 sub_len, is_unicode, nls_codepage);
3186 goto qreparse_out;
3187 } else if (reparse_buf->ReparseTag !=
3188 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3189 rc = -EOPNOTSUPP;
3190 goto qreparse_out;
3191 }
3192
3193 /* Reparse tag is NTFS symlink */
3194 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3195 reparse_buf->PathBuffer;
3196 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3197 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003198 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3199 rc = -EIO;
3200 goto qreparse_out;
3201 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003202 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3203 is_unicode = true;
3204 else
3205 is_unicode = false;
3206
3207 /* BB FIXME investigate remapping reserved chars here */
3208 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3209 nls_codepage);
3210 if (!*symlinkinfo)
3211 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003213 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003215 /*
3216 * Note: On -EAGAIN error only caller can retry on handle based calls
3217 * since file handle passed in no longer valid.
3218 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 return rc;
3220}
3221
Steve Frenchc7f508a2013-10-14 15:27:32 -05003222int
3223CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3224 __u16 fid)
3225{
3226 int rc = 0;
3227 int bytes_returned;
3228 struct smb_com_transaction_compr_ioctl_req *pSMB;
3229 struct smb_com_transaction_ioctl_rsp *pSMBr;
3230
3231 cifs_dbg(FYI, "Set compression for %u\n", fid);
3232 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3233 (void **) &pSMBr);
3234 if (rc)
3235 return rc;
3236
3237 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3238
3239 pSMB->TotalParameterCount = 0;
3240 pSMB->TotalDataCount = __constant_cpu_to_le32(2);
3241 pSMB->MaxParameterCount = 0;
3242 pSMB->MaxDataCount = 0;
3243 pSMB->MaxSetupCount = 4;
3244 pSMB->Reserved = 0;
3245 pSMB->ParameterOffset = 0;
3246 pSMB->DataCount = __constant_cpu_to_le32(2);
3247 pSMB->DataOffset =
3248 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3249 compression_state) - 4); /* 84 */
3250 pSMB->SetupCount = 4;
3251 pSMB->SubCommand = __constant_cpu_to_le16(NT_TRANSACT_IOCTL);
3252 pSMB->ParameterCount = 0;
3253 pSMB->FunctionCode = __constant_cpu_to_le32(FSCTL_SET_COMPRESSION);
3254 pSMB->IsFsctl = 1; /* FSCTL */
3255 pSMB->IsRootFlag = 0;
3256 pSMB->Fid = fid; /* file handle always le */
3257 /* 3 byte pad, followed by 2 byte compress state */
3258 pSMB->ByteCount = __constant_cpu_to_le16(5);
3259 inc_rfc1001_len(pSMB, 5);
3260
3261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3263 if (rc)
3264 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3265
3266 cifs_buf_release(pSMB);
3267
3268 /*
3269 * Note: On -EAGAIN error only caller can retry on handle based calls
3270 * since file handle passed in no longer valid.
3271 */
3272 return rc;
3273}
3274
3275
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276#ifdef CONFIG_CIFS_POSIX
3277
3278/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003279static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3280 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281{
3282 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003283 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3284 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3285 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003286/*
3287 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3288 ace->e_perm, ace->e_tag, ace->e_id);
3289*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
3291 return;
3292}
3293
3294/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003295static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3296 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297{
3298 int size = 0;
3299 int i;
3300 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003301 struct cifs_posix_ace *pACE;
3302 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3303 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304
3305 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3306 return -EOPNOTSUPP;
3307
Steve French790fe572007-07-07 19:25:05 +00003308 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 count = le16_to_cpu(cifs_acl->access_entry_count);
3310 pACE = &cifs_acl->ace_array[0];
3311 size = sizeof(struct cifs_posix_acl);
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) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003315 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3316 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 return -EINVAL;
3318 }
Steve French790fe572007-07-07 19:25:05 +00003319 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 count = le16_to_cpu(cifs_acl->access_entry_count);
3321 size = sizeof(struct cifs_posix_acl);
3322 size += sizeof(struct cifs_posix_ace) * count;
3323/* skip past access ACEs to get to default ACEs */
3324 pACE = &cifs_acl->ace_array[count];
3325 count = le16_to_cpu(cifs_acl->default_entry_count);
3326 size += sizeof(struct cifs_posix_ace) * count;
3327 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003328 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 return -EINVAL;
3330 } else {
3331 /* illegal type */
3332 return -EINVAL;
3333 }
3334
3335 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003336 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003337 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003338 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 return -ERANGE;
3340 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003341 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003342 for (i = 0; i < count ; i++) {
3343 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3344 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 }
3346 }
3347 return size;
3348}
3349
Steve French50c2f752007-07-13 00:33:32 +00003350static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3351 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352{
3353 __u16 rc = 0; /* 0 = ACL converted ok */
3354
Steve Frenchff7feac2005-11-15 16:45:16 -08003355 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3356 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003358 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 /* Probably no need to le convert -1 on any arch but can not hurt */
3360 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003361 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003362 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003363/*
3364 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3365 ace->e_perm, ace->e_tag, ace->e_id);
3366*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 return rc;
3368}
3369
3370/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003371static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3372 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373{
3374 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003375 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3376 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 int count;
3378 int i;
3379
Steve French790fe572007-07-07 19:25:05 +00003380 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 return 0;
3382
3383 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003384 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3385 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003386 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003387 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3388 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 return 0;
3390 }
3391 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003392 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003393 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve Frenchb1d93352013-11-15 20:41:32 -06003394 cifs_acl->default_entry_count = __constant_cpu_to_le16(0xFFFF);
3395 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003396 cifs_acl->default_entry_count = cpu_to_le16(count);
Steve Frenchb1d93352013-11-15 20:41:32 -06003397 cifs_acl->access_entry_count = __constant_cpu_to_le16(0xFFFF);
3398 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003399 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 return 0;
3401 }
Steve French50c2f752007-07-13 00:33:32 +00003402 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3404 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003405 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 /* ACE not converted */
3407 break;
3408 }
3409 }
Steve French790fe572007-07-07 19:25:05 +00003410 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3412 rc += sizeof(struct cifs_posix_acl);
3413 /* BB add check to make sure ACL does not overflow SMB */
3414 }
3415 return rc;
3416}
3417
3418int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003419CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003420 const unsigned char *searchName,
3421 char *acl_inf, const int buflen, const int acl_type,
3422 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423{
3424/* SMB_QUERY_POSIX_ACL */
3425 TRANSACTION2_QPI_REQ *pSMB = NULL;
3426 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3427 int rc = 0;
3428 int bytes_returned;
3429 int name_len;
3430 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003431
Joe Perchesf96637b2013-05-04 22:12:25 -05003432 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433
3434queryAclRetry:
3435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3436 (void **) &pSMBr);
3437 if (rc)
3438 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003439
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3441 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003442 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3443 searchName, PATH_MAX, nls_codepage,
3444 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 name_len++; /* trailing null */
3446 name_len *= 2;
3447 pSMB->FileName[name_len] = 0;
3448 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003449 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 name_len = strnlen(searchName, PATH_MAX);
3451 name_len++; /* trailing null */
3452 strncpy(pSMB->FileName, searchName, name_len);
3453 }
3454
3455 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3456 pSMB->TotalDataCount = 0;
3457 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003458 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 pSMB->MaxDataCount = cpu_to_le16(4000);
3460 pSMB->MaxSetupCount = 0;
3461 pSMB->Reserved = 0;
3462 pSMB->Flags = 0;
3463 pSMB->Timeout = 0;
3464 pSMB->Reserved2 = 0;
3465 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003466 offsetof(struct smb_com_transaction2_qpi_req,
3467 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 pSMB->DataCount = 0;
3469 pSMB->DataOffset = 0;
3470 pSMB->SetupCount = 1;
3471 pSMB->Reserved3 = 0;
3472 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3473 byte_count = params + 1 /* pad */ ;
3474 pSMB->TotalParameterCount = cpu_to_le16(params);
3475 pSMB->ParameterCount = pSMB->TotalParameterCount;
3476 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3477 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003478 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 pSMB->ByteCount = cpu_to_le16(byte_count);
3480
3481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3482 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003483 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003485 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 } else {
3487 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003488
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003491 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 rc = -EIO; /* bad smb */
3493 else {
3494 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3495 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3496 rc = cifs_copy_posix_acl(acl_inf,
3497 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003498 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 }
3500 }
3501 cifs_buf_release(pSMB);
3502 if (rc == -EAGAIN)
3503 goto queryAclRetry;
3504 return rc;
3505}
3506
3507int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003508CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003509 const unsigned char *fileName,
3510 const char *local_acl, const int buflen,
3511 const int acl_type,
3512 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513{
3514 struct smb_com_transaction2_spi_req *pSMB = NULL;
3515 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3516 char *parm_data;
3517 int name_len;
3518 int rc = 0;
3519 int bytes_returned = 0;
3520 __u16 params, byte_count, data_count, param_offset, offset;
3521
Joe Perchesf96637b2013-05-04 22:12:25 -05003522 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523setAclRetry:
3524 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003525 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 if (rc)
3527 return rc;
3528 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3529 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003530 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3531 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 name_len++; /* trailing null */
3533 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003534 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 name_len = strnlen(fileName, PATH_MAX);
3536 name_len++; /* trailing null */
3537 strncpy(pSMB->FileName, fileName, name_len);
3538 }
3539 params = 6 + name_len;
3540 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003541 /* BB find max SMB size from sess */
3542 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 pSMB->MaxSetupCount = 0;
3544 pSMB->Reserved = 0;
3545 pSMB->Flags = 0;
3546 pSMB->Timeout = 0;
3547 pSMB->Reserved2 = 0;
3548 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003549 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 offset = param_offset + params;
3551 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3552 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3553
3554 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003555 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556
Steve French790fe572007-07-07 19:25:05 +00003557 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 rc = -EOPNOTSUPP;
3559 goto setACLerrorExit;
3560 }
3561 pSMB->DataOffset = cpu_to_le16(offset);
3562 pSMB->SetupCount = 1;
3563 pSMB->Reserved3 = 0;
3564 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3565 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3566 byte_count = 3 /* pad */ + params + data_count;
3567 pSMB->DataCount = cpu_to_le16(data_count);
3568 pSMB->TotalDataCount = pSMB->DataCount;
3569 pSMB->ParameterCount = cpu_to_le16(params);
3570 pSMB->TotalParameterCount = pSMB->ParameterCount;
3571 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003572 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 pSMB->ByteCount = cpu_to_le16(byte_count);
3574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003576 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003577 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578
3579setACLerrorExit:
3580 cifs_buf_release(pSMB);
3581 if (rc == -EAGAIN)
3582 goto setAclRetry;
3583 return rc;
3584}
3585
Steve Frenchf654bac2005-04-28 22:41:04 -07003586/* BB fix tabs in this function FIXME BB */
3587int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003588CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003589 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003590{
Steve French50c2f752007-07-13 00:33:32 +00003591 int rc = 0;
3592 struct smb_t2_qfi_req *pSMB = NULL;
3593 struct smb_t2_qfi_rsp *pSMBr = NULL;
3594 int bytes_returned;
3595 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003596
Joe Perchesf96637b2013-05-04 22:12:25 -05003597 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003598 if (tcon == NULL)
3599 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003600
3601GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003602 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3603 (void **) &pSMBr);
3604 if (rc)
3605 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003606
Steve Frenchad7a2922008-02-07 23:25:02 +00003607 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003608 pSMB->t2.TotalDataCount = 0;
3609 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3610 /* BB find exact max data count below from sess structure BB */
3611 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3612 pSMB->t2.MaxSetupCount = 0;
3613 pSMB->t2.Reserved = 0;
3614 pSMB->t2.Flags = 0;
3615 pSMB->t2.Timeout = 0;
3616 pSMB->t2.Reserved2 = 0;
3617 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3618 Fid) - 4);
3619 pSMB->t2.DataCount = 0;
3620 pSMB->t2.DataOffset = 0;
3621 pSMB->t2.SetupCount = 1;
3622 pSMB->t2.Reserved3 = 0;
3623 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3624 byte_count = params + 1 /* pad */ ;
3625 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3626 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3627 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3628 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003629 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003630 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003631 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003632
Steve French790fe572007-07-07 19:25:05 +00003633 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3634 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3635 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003636 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003637 } else {
3638 /* decode response */
3639 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003640 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003641 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003642 /* If rc should we check for EOPNOSUPP and
3643 disable the srvino flag? or in caller? */
3644 rc = -EIO; /* bad smb */
3645 else {
3646 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3647 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3648 struct file_chattr_info *pfinfo;
3649 /* BB Do we need a cast or hash here ? */
3650 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003651 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003652 rc = -EIO;
3653 goto GetExtAttrOut;
3654 }
3655 pfinfo = (struct file_chattr_info *)
3656 (data_offset + (char *) &pSMBr->hdr.Protocol);
3657 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003658 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003659 }
3660 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003661GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003662 cifs_buf_release(pSMB);
3663 if (rc == -EAGAIN)
3664 goto GetExtAttrRetry;
3665 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003666}
3667
Steve Frenchf654bac2005-04-28 22:41:04 -07003668#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
Jeff Layton79df1ba2010-12-06 12:52:08 -05003670#ifdef CONFIG_CIFS_ACL
3671/*
3672 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3673 * all NT TRANSACTS that we init here have total parm and data under about 400
3674 * bytes (to fit in small cifs buffer size), which is the case so far, it
3675 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3676 * returned setup area) and MaxParameterCount (returned parms size) must be set
3677 * by caller
3678 */
3679static int
3680smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003681 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003682 void **ret_buf)
3683{
3684 int rc;
3685 __u32 temp_offset;
3686 struct smb_com_ntransact_req *pSMB;
3687
3688 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3689 (void **)&pSMB);
3690 if (rc)
3691 return rc;
3692 *ret_buf = (void *)pSMB;
3693 pSMB->Reserved = 0;
3694 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3695 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003696 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003697 pSMB->ParameterCount = pSMB->TotalParameterCount;
3698 pSMB->DataCount = pSMB->TotalDataCount;
3699 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3700 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3701 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3702 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3703 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3704 pSMB->SubCommand = cpu_to_le16(sub_command);
3705 return 0;
3706}
3707
3708static int
3709validate_ntransact(char *buf, char **ppparm, char **ppdata,
3710 __u32 *pparmlen, __u32 *pdatalen)
3711{
3712 char *end_of_smb;
3713 __u32 data_count, data_offset, parm_count, parm_offset;
3714 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003715 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003716
3717 *pdatalen = 0;
3718 *pparmlen = 0;
3719
3720 if (buf == NULL)
3721 return -EINVAL;
3722
3723 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3724
Jeff Layton820a8032011-05-04 08:05:26 -04003725 bcc = get_bcc(&pSMBr->hdr);
3726 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003727 (char *)&pSMBr->ByteCount;
3728
3729 data_offset = le32_to_cpu(pSMBr->DataOffset);
3730 data_count = le32_to_cpu(pSMBr->DataCount);
3731 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3732 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3733
3734 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3735 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3736
3737 /* should we also check that parm and data areas do not overlap? */
3738 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003739 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003740 return -EINVAL;
3741 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003742 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003743 return -EINVAL;
3744 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003745 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003746 return -EINVAL;
3747 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003748 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3749 *ppdata, data_count, (data_count + *ppdata),
3750 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003751 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003752 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003753 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003754 return -EINVAL;
3755 }
3756 *pdatalen = data_count;
3757 *pparmlen = parm_count;
3758 return 0;
3759}
3760
Steve French0a4b92c2006-01-12 15:44:21 -08003761/* Get Security Descriptor (by handle) from remote server for a file or dir */
3762int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003763CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003764 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003765{
3766 int rc = 0;
3767 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003768 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003769 struct kvec iov[1];
3770
Joe Perchesf96637b2013-05-04 22:12:25 -05003771 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003772
Steve French630f3f0c2007-10-25 21:17:17 +00003773 *pbuflen = 0;
3774 *acl_inf = NULL;
3775
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003776 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003777 8 /* parm len */, tcon, (void **) &pSMB);
3778 if (rc)
3779 return rc;
3780
3781 pSMB->MaxParameterCount = cpu_to_le32(4);
3782 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3783 pSMB->MaxSetupCount = 0;
3784 pSMB->Fid = fid; /* file handle always le */
3785 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3786 CIFS_ACL_DACL);
3787 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003788 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003789 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003790 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003791
Steve Frencha761ac52007-10-18 21:45:27 +00003792 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003793 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003794 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003795 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003796 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003797 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003798 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003799 __u32 parm_len;
3800 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003801 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003802 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003803
3804/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003805 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003806 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003807 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003808 goto qsec_out;
3809 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3810
Joe Perchesf96637b2013-05-04 22:12:25 -05003811 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3812 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003813
3814 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3815 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003816 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003817 goto qsec_out;
3818 }
3819
3820/* BB check that data area is minimum length and as big as acl_len */
3821
Steve Frenchaf6f4612007-10-16 18:40:37 +00003822 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003823 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003824 cifs_dbg(VFS, "acl length %d does not match %d\n",
3825 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003826 if (*pbuflen > acl_len)
3827 *pbuflen = acl_len;
3828 }
Steve French0a4b92c2006-01-12 15:44:21 -08003829
Steve French630f3f0c2007-10-25 21:17:17 +00003830 /* check if buffer is big enough for the acl
3831 header followed by the smallest SID */
3832 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3833 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003834 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003835 rc = -EINVAL;
3836 *pbuflen = 0;
3837 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003838 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003839 if (*acl_inf == NULL) {
3840 *pbuflen = 0;
3841 rc = -ENOMEM;
3842 }
Steve French630f3f0c2007-10-25 21:17:17 +00003843 }
Steve French0a4b92c2006-01-12 15:44:21 -08003844 }
3845qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003846 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003847 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003848 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003849 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003850/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003851 return rc;
3852}
Steve French97837582007-12-31 07:47:21 +00003853
3854int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003855CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003856 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003857{
3858 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3859 int rc = 0;
3860 int bytes_returned = 0;
3861 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003862 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003863
3864setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003865 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003866 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003867 return rc;
Steve French97837582007-12-31 07:47:21 +00003868
3869 pSMB->MaxSetupCount = 0;
3870 pSMB->Reserved = 0;
3871
3872 param_count = 8;
3873 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3874 data_count = acllen;
3875 data_offset = param_offset + param_count;
3876 byte_count = 3 /* pad */ + param_count;
3877
3878 pSMB->DataCount = cpu_to_le32(data_count);
3879 pSMB->TotalDataCount = pSMB->DataCount;
3880 pSMB->MaxParameterCount = cpu_to_le32(4);
3881 pSMB->MaxDataCount = cpu_to_le32(16384);
3882 pSMB->ParameterCount = cpu_to_le32(param_count);
3883 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3884 pSMB->TotalParameterCount = pSMB->ParameterCount;
3885 pSMB->DataOffset = cpu_to_le32(data_offset);
3886 pSMB->SetupCount = 0;
3887 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3888 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3889
3890 pSMB->Fid = fid; /* file handle always le */
3891 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003892 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003893
3894 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003895 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3896 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003897 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003898 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003899 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003900
3901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3903
Joe Perchesf96637b2013-05-04 22:12:25 -05003904 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3905 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003906 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003907 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003908 cifs_buf_release(pSMB);
3909
3910 if (rc == -EAGAIN)
3911 goto setCifsAclRetry;
3912
3913 return (rc);
3914}
3915
Jeff Layton79df1ba2010-12-06 12:52:08 -05003916#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003917
Steve French6b8edfe2005-08-23 20:26:03 -07003918/* Legacy Query Path Information call for lookup to old servers such
3919 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003920int
3921SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3922 const char *search_name, FILE_ALL_INFO *data,
3923 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003924{
Steve Frenchad7a2922008-02-07 23:25:02 +00003925 QUERY_INFORMATION_REQ *pSMB;
3926 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003927 int rc = 0;
3928 int bytes_returned;
3929 int name_len;
3930
Joe Perchesf96637b2013-05-04 22:12:25 -05003931 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003932QInfRetry:
3933 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003934 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003935 if (rc)
3936 return rc;
3937
3938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3939 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003940 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003941 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003942 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003943 name_len++; /* trailing null */
3944 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003945 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003946 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003947 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003948 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003949 }
3950 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003951 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003952 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003953 pSMB->ByteCount = cpu_to_le16(name_len);
3954
3955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003957 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003958 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003959 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003960 struct timespec ts;
3961 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003962
3963 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003964 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003965 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003966 ts.tv_nsec = 0;
3967 ts.tv_sec = time;
3968 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003969 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3970 data->LastWriteTime = data->ChangeTime;
3971 data->LastAccessTime = 0;
3972 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003973 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003974 data->EndOfFile = data->AllocationSize;
3975 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003976 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003977 } else
3978 rc = -EIO; /* bad buffer passed in */
3979
3980 cifs_buf_release(pSMB);
3981
3982 if (rc == -EAGAIN)
3983 goto QInfRetry;
3984
3985 return rc;
3986}
3987
Jeff Laytonbcd53572010-02-12 07:44:16 -05003988int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003989CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003990 u16 netfid, FILE_ALL_INFO *pFindData)
3991{
3992 struct smb_t2_qfi_req *pSMB = NULL;
3993 struct smb_t2_qfi_rsp *pSMBr = NULL;
3994 int rc = 0;
3995 int bytes_returned;
3996 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003997
Jeff Laytonbcd53572010-02-12 07:44:16 -05003998QFileInfoRetry:
3999 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4000 (void **) &pSMBr);
4001 if (rc)
4002 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004003
Jeff Laytonbcd53572010-02-12 07:44:16 -05004004 params = 2 /* level */ + 2 /* fid */;
4005 pSMB->t2.TotalDataCount = 0;
4006 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4007 /* BB find exact max data count below from sess structure BB */
4008 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4009 pSMB->t2.MaxSetupCount = 0;
4010 pSMB->t2.Reserved = 0;
4011 pSMB->t2.Flags = 0;
4012 pSMB->t2.Timeout = 0;
4013 pSMB->t2.Reserved2 = 0;
4014 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4015 Fid) - 4);
4016 pSMB->t2.DataCount = 0;
4017 pSMB->t2.DataOffset = 0;
4018 pSMB->t2.SetupCount = 1;
4019 pSMB->t2.Reserved3 = 0;
4020 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4021 byte_count = params + 1 /* pad */ ;
4022 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4023 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4025 pSMB->Pad = 0;
4026 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004027 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004028 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004029
4030 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4031 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4032 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004033 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004034 } else { /* decode response */
4035 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4036
4037 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4038 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004039 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004040 rc = -EIO; /* bad smb */
4041 else if (pFindData) {
4042 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4043 memcpy((char *) pFindData,
4044 (char *) &pSMBr->hdr.Protocol +
4045 data_offset, sizeof(FILE_ALL_INFO));
4046 } else
4047 rc = -ENOMEM;
4048 }
4049 cifs_buf_release(pSMB);
4050 if (rc == -EAGAIN)
4051 goto QFileInfoRetry;
4052
4053 return rc;
4054}
Steve French6b8edfe2005-08-23 20:26:03 -07004055
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004057CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004058 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004059 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004060 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004062 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 TRANSACTION2_QPI_REQ *pSMB = NULL;
4064 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4065 int rc = 0;
4066 int bytes_returned;
4067 int name_len;
4068 __u16 params, byte_count;
4069
Joe Perchesf96637b2013-05-04 22:12:25 -05004070 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071QPathInfoRetry:
4072 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4073 (void **) &pSMBr);
4074 if (rc)
4075 return rc;
4076
4077 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4078 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004079 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004080 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 name_len++; /* trailing null */
4082 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004083 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004084 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004086 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 }
4088
Steve French50c2f752007-07-13 00:33:32 +00004089 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 pSMB->TotalDataCount = 0;
4091 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004092 /* BB find exact max SMB PDU from sess structure BB */
4093 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 pSMB->MaxSetupCount = 0;
4095 pSMB->Reserved = 0;
4096 pSMB->Flags = 0;
4097 pSMB->Timeout = 0;
4098 pSMB->Reserved2 = 0;
4099 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004100 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 pSMB->DataCount = 0;
4102 pSMB->DataOffset = 0;
4103 pSMB->SetupCount = 1;
4104 pSMB->Reserved3 = 0;
4105 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4106 byte_count = params + 1 /* pad */ ;
4107 pSMB->TotalParameterCount = cpu_to_le16(params);
4108 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004109 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004110 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4111 else
4112 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004114 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 pSMB->ByteCount = cpu_to_le16(byte_count);
4116
4117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4119 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004120 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 } else { /* decode response */
4122 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4123
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004124 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4125 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004126 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004128 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004129 rc = -EIO; /* 24 or 26 expected but we do not read
4130 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004131 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004132 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004134
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004135 /*
4136 * On legacy responses we do not read the last field,
4137 * EAsize, fortunately since it varies by subdialect and
4138 * also note it differs on Set vs Get, ie two bytes or 4
4139 * bytes depending but we don't care here.
4140 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004141 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004142 size = sizeof(FILE_INFO_STANDARD);
4143 else
4144 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004145 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004146 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 } else
4148 rc = -ENOMEM;
4149 }
4150 cifs_buf_release(pSMB);
4151 if (rc == -EAGAIN)
4152 goto QPathInfoRetry;
4153
4154 return rc;
4155}
4156
4157int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004158CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004159 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4160{
4161 struct smb_t2_qfi_req *pSMB = NULL;
4162 struct smb_t2_qfi_rsp *pSMBr = NULL;
4163 int rc = 0;
4164 int bytes_returned;
4165 __u16 params, byte_count;
4166
4167UnixQFileInfoRetry:
4168 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4169 (void **) &pSMBr);
4170 if (rc)
4171 return rc;
4172
4173 params = 2 /* level */ + 2 /* fid */;
4174 pSMB->t2.TotalDataCount = 0;
4175 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4176 /* BB find exact max data count below from sess structure BB */
4177 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4178 pSMB->t2.MaxSetupCount = 0;
4179 pSMB->t2.Reserved = 0;
4180 pSMB->t2.Flags = 0;
4181 pSMB->t2.Timeout = 0;
4182 pSMB->t2.Reserved2 = 0;
4183 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4184 Fid) - 4);
4185 pSMB->t2.DataCount = 0;
4186 pSMB->t2.DataOffset = 0;
4187 pSMB->t2.SetupCount = 1;
4188 pSMB->t2.Reserved3 = 0;
4189 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4190 byte_count = params + 1 /* pad */ ;
4191 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4192 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4193 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4194 pSMB->Pad = 0;
4195 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004196 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004197 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004198
4199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4201 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004202 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004203 } else { /* decode response */
4204 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4205
Jeff Layton820a8032011-05-04 08:05:26 -04004206 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004207 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 -05004208 rc = -EIO; /* bad smb */
4209 } else {
4210 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4211 memcpy((char *) pFindData,
4212 (char *) &pSMBr->hdr.Protocol +
4213 data_offset,
4214 sizeof(FILE_UNIX_BASIC_INFO));
4215 }
4216 }
4217
4218 cifs_buf_release(pSMB);
4219 if (rc == -EAGAIN)
4220 goto UnixQFileInfoRetry;
4221
4222 return rc;
4223}
4224
4225int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004226CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004228 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004229 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230{
4231/* SMB_QUERY_FILE_UNIX_BASIC */
4232 TRANSACTION2_QPI_REQ *pSMB = NULL;
4233 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4234 int rc = 0;
4235 int bytes_returned = 0;
4236 int name_len;
4237 __u16 params, byte_count;
4238
Joe Perchesf96637b2013-05-04 22:12:25 -05004239 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240UnixQPathInfoRetry:
4241 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4242 (void **) &pSMBr);
4243 if (rc)
4244 return rc;
4245
4246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4247 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004248 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4249 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 name_len++; /* trailing null */
4251 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004252 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 name_len = strnlen(searchName, PATH_MAX);
4254 name_len++; /* trailing null */
4255 strncpy(pSMB->FileName, searchName, name_len);
4256 }
4257
Steve French50c2f752007-07-13 00:33:32 +00004258 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 pSMB->TotalDataCount = 0;
4260 pSMB->MaxParameterCount = cpu_to_le16(2);
4261 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004262 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 pSMB->MaxSetupCount = 0;
4264 pSMB->Reserved = 0;
4265 pSMB->Flags = 0;
4266 pSMB->Timeout = 0;
4267 pSMB->Reserved2 = 0;
4268 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004269 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 pSMB->DataCount = 0;
4271 pSMB->DataOffset = 0;
4272 pSMB->SetupCount = 1;
4273 pSMB->Reserved3 = 0;
4274 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4275 byte_count = params + 1 /* pad */ ;
4276 pSMB->TotalParameterCount = cpu_to_le16(params);
4277 pSMB->ParameterCount = pSMB->TotalParameterCount;
4278 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4279 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004280 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 pSMB->ByteCount = cpu_to_le16(byte_count);
4282
4283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4285 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004286 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 } else { /* decode response */
4288 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4289
Jeff Layton820a8032011-05-04 08:05:26 -04004290 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004291 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 -07004292 rc = -EIO; /* bad smb */
4293 } else {
4294 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4295 memcpy((char *) pFindData,
4296 (char *) &pSMBr->hdr.Protocol +
4297 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004298 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 }
4300 }
4301 cifs_buf_release(pSMB);
4302 if (rc == -EAGAIN)
4303 goto UnixQPathInfoRetry;
4304
4305 return rc;
4306}
4307
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308/* xid, tcon, searchName and codepage are input parms, rest are returned */
4309int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004310CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004311 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004312 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004313 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314{
4315/* level 257 SMB_ */
4316 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4317 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004318 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 int rc = 0;
4320 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004321 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004323 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
Joe Perchesf96637b2013-05-04 22:12:25 -05004325 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326
4327findFirstRetry:
4328 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4329 (void **) &pSMBr);
4330 if (rc)
4331 return rc;
4332
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004333 nls_codepage = cifs_sb->local_nls;
4334 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4335
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4337 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004338 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4339 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004340 /* We can not add the asterik earlier in case
4341 it got remapped to 0xF03A as if it were part of the
4342 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 name_len *= 2;
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] = 0;
4347 pSMB->FileName[name_len+2] = '*';
4348 pSMB->FileName[name_len+3] = 0;
4349 name_len += 4; /* now the trailing null */
4350 /* null terminate just in case */
4351 pSMB->FileName[name_len] = 0;
4352 pSMB->FileName[name_len+1] = 0;
4353 name_len += 2;
4354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 } else { /* BB add check for overrun of SMB buf BB */
4356 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004358 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 free buffer exit; BB */
4360 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004361 if (msearch) {
4362 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4363 pSMB->FileName[name_len+1] = '*';
4364 pSMB->FileName[name_len+2] = 0;
4365 name_len += 3;
4366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 }
4368
4369 params = 12 + name_len /* includes null */ ;
4370 pSMB->TotalDataCount = 0; /* no EAs */
4371 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004372 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 pSMB->MaxSetupCount = 0;
4374 pSMB->Reserved = 0;
4375 pSMB->Flags = 0;
4376 pSMB->Timeout = 0;
4377 pSMB->Reserved2 = 0;
4378 byte_count = params + 1 /* pad */ ;
4379 pSMB->TotalParameterCount = cpu_to_le16(params);
4380 pSMB->ParameterCount = pSMB->TotalParameterCount;
4381 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004382 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4383 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 pSMB->DataCount = 0;
4385 pSMB->DataOffset = 0;
4386 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4387 pSMB->Reserved3 = 0;
4388 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4389 pSMB->SearchAttributes =
4390 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4391 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004392 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004393 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4395
4396 /* BB what should we set StorageType to? Does it matter? BB */
4397 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004398 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399 pSMB->ByteCount = cpu_to_le16(byte_count);
4400
4401 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004403 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404
Steve French88274812006-03-09 22:21:45 +00004405 if (rc) {/* BB add logic to retry regular search if Unix search
4406 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004408 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004409
Steve French88274812006-03-09 22:21:45 +00004410 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411
4412 /* BB eventually could optimize out free and realloc of buf */
4413 /* for this case */
4414 if (rc == -EAGAIN)
4415 goto findFirstRetry;
4416 } else { /* decode response */
4417 /* BB remember to free buffer if error BB */
4418 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004419 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004420 unsigned int lnoff;
4421
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004423 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 else
Steve French4b18f2a2008-04-29 00:06:05 +00004425 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426
4427 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004428 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004429 psrch_inf->srch_entries_start =
4430 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4433 le16_to_cpu(pSMBr->t2.ParameterOffset));
4434
Steve French790fe572007-07-07 19:25:05 +00004435 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004436 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 else
Steve French4b18f2a2008-04-29 00:06:05 +00004438 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439
Steve French50c2f752007-07-13 00:33:32 +00004440 psrch_inf->entries_in_buffer =
4441 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004442 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004444 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004445 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004446 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004447 psrch_inf->last_entry = NULL;
4448 return rc;
4449 }
4450
Steve French0752f152008-10-07 20:03:33 +00004451 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004452 lnoff;
4453
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004454 if (pnetfid)
4455 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 } else {
4457 cifs_buf_release(pSMB);
4458 }
4459 }
4460
4461 return rc;
4462}
4463
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004464int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4465 __u16 searchHandle, __u16 search_flags,
4466 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467{
4468 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4469 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004470 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 char *response_data;
4472 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004473 int bytes_returned;
4474 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 __u16 params, byte_count;
4476
Joe Perchesf96637b2013-05-04 22:12:25 -05004477 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478
Steve French4b18f2a2008-04-29 00:06:05 +00004479 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 return -ENOENT;
4481
4482 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4483 (void **) &pSMBr);
4484 if (rc)
4485 return rc;
4486
Steve French50c2f752007-07-13 00:33:32 +00004487 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 byte_count = 0;
4489 pSMB->TotalDataCount = 0; /* no EAs */
4490 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004491 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 pSMB->MaxSetupCount = 0;
4493 pSMB->Reserved = 0;
4494 pSMB->Flags = 0;
4495 pSMB->Timeout = 0;
4496 pSMB->Reserved2 = 0;
4497 pSMB->ParameterOffset = cpu_to_le16(
4498 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4499 pSMB->DataCount = 0;
4500 pSMB->DataOffset = 0;
4501 pSMB->SetupCount = 1;
4502 pSMB->Reserved3 = 0;
4503 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4504 pSMB->SearchHandle = searchHandle; /* always kept as le */
4505 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004506 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4508 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004509 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510
4511 name_len = psrch_inf->resume_name_len;
4512 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004513 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4515 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004516 /* 14 byte parm len above enough for 2 byte null terminator */
4517 pSMB->ResumeFileName[name_len] = 0;
4518 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 } else {
4520 rc = -EINVAL;
4521 goto FNext2_err_exit;
4522 }
4523 byte_count = params + 1 /* pad */ ;
4524 pSMB->TotalParameterCount = cpu_to_le16(params);
4525 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004526 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004528
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4530 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004531 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 if (rc) {
4533 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004534 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004535 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004536 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004538 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 } else { /* decode response */
4540 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004541
Steve French790fe572007-07-07 19:25:05 +00004542 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004543 unsigned int lnoff;
4544
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 /* BB fixme add lock for file (srch_info) struct here */
4546 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004547 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 else
Steve French4b18f2a2008-04-29 00:06:05 +00004549 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 response_data = (char *) &pSMBr->hdr.Protocol +
4551 le16_to_cpu(pSMBr->t2.ParameterOffset);
4552 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4553 response_data = (char *)&pSMBr->hdr.Protocol +
4554 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004555 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004556 cifs_small_buf_release(
4557 psrch_inf->ntwrk_buf_start);
4558 else
4559 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 psrch_inf->srch_entries_start = response_data;
4561 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004562 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004563 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004564 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 else
Steve French4b18f2a2008-04-29 00:06:05 +00004566 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004567 psrch_inf->entries_in_buffer =
4568 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 psrch_inf->index_of_last_entry +=
4570 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004571 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004572 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004573 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004574 psrch_inf->last_entry = NULL;
4575 return rc;
4576 } else
4577 psrch_inf->last_entry =
4578 psrch_inf->srch_entries_start + lnoff;
4579
Joe Perchesf96637b2013-05-04 22:12:25 -05004580/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4581 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
4583 /* BB fixme add unlock here */
4584 }
4585
4586 }
4587
4588 /* BB On error, should we leave previous search buf (and count and
4589 last entry fields) intact or free the previous one? */
4590
4591 /* Note: On -EAGAIN error only caller can retry on handle based calls
4592 since file handle passed in no longer valid */
4593FNext2_err_exit:
4594 if (rc != 0)
4595 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 return rc;
4597}
4598
4599int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004600CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004601 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602{
4603 int rc = 0;
4604 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605
Joe Perchesf96637b2013-05-04 22:12:25 -05004606 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4608
4609 /* no sense returning error if session restarted
4610 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004611 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 return 0;
4613 if (rc)
4614 return rc;
4615
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 pSMB->FileID = searchHandle;
4617 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004618 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004619 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004620 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004621
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004622 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
4624 /* Since session is dead, search handle closed on server already */
4625 if (rc == -EAGAIN)
4626 rc = 0;
4627
4628 return rc;
4629}
4630
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004632CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004633 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004634 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635{
4636 int rc = 0;
4637 TRANSACTION2_QPI_REQ *pSMB = NULL;
4638 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4639 int name_len, bytes_returned;
4640 __u16 params, byte_count;
4641
Joe Perchesf96637b2013-05-04 22:12:25 -05004642 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004643 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004644 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
4646GetInodeNumberRetry:
4647 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004648 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 if (rc)
4650 return rc;
4651
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4653 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004654 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004655 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004656 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 name_len++; /* trailing null */
4658 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004659 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004660 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004662 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 }
4664
4665 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4666 pSMB->TotalDataCount = 0;
4667 pSMB->MaxParameterCount = cpu_to_le16(2);
4668 /* BB find exact max data count below from sess structure BB */
4669 pSMB->MaxDataCount = cpu_to_le16(4000);
4670 pSMB->MaxSetupCount = 0;
4671 pSMB->Reserved = 0;
4672 pSMB->Flags = 0;
4673 pSMB->Timeout = 0;
4674 pSMB->Reserved2 = 0;
4675 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004676 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 pSMB->DataCount = 0;
4678 pSMB->DataOffset = 0;
4679 pSMB->SetupCount = 1;
4680 pSMB->Reserved3 = 0;
4681 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4682 byte_count = params + 1 /* pad */ ;
4683 pSMB->TotalParameterCount = cpu_to_le16(params);
4684 pSMB->ParameterCount = pSMB->TotalParameterCount;
4685 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4686 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004687 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 pSMB->ByteCount = cpu_to_le16(byte_count);
4689
4690 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4691 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4692 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004693 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 } else {
4695 /* decode response */
4696 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004698 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 /* If rc should we check for EOPNOSUPP and
4700 disable the srvino flag? or in caller? */
4701 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004702 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4704 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004705 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004707 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004708 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 rc = -EIO;
4710 goto GetInodeNumOut;
4711 }
4712 pfinfo = (struct file_internal_info *)
4713 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004714 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 }
4716 }
4717GetInodeNumOut:
4718 cifs_buf_release(pSMB);
4719 if (rc == -EAGAIN)
4720 goto GetInodeNumberRetry;
4721 return rc;
4722}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723
Igor Mammedovfec45852008-05-16 13:06:30 +04004724/* parses DFS refferal V3 structure
4725 * caller is responsible for freeing target_nodes
4726 * returns:
4727 * on success - 0
4728 * on failure - errno
4729 */
4730static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004731parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004732 unsigned int *num_of_nodes,
4733 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004734 const struct nls_table *nls_codepage, int remap,
4735 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004736{
4737 int i, rc = 0;
4738 char *data_end;
4739 bool is_unicode;
4740 struct dfs_referral_level_3 *ref;
4741
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004742 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4743 is_unicode = true;
4744 else
4745 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004746 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4747
4748 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004749 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4750 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004751 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004752 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004753 }
4754
4755 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004756 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004757 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4758 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004759 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004760 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004761 }
4762
4763 /* get the upper boundary of the resp buffer */
4764 data_end = (char *)(&(pSMBr->PathConsumed)) +
4765 le16_to_cpu(pSMBr->t2.DataCount);
4766
Joe Perchesf96637b2013-05-04 22:12:25 -05004767 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4768 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004769
Joe Perchesf96637b2013-05-04 22:12:25 -05004770 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4771 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004772 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004773 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004774 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004775 }
4776
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004777 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004778 for (i = 0; i < *num_of_nodes; i++) {
4779 char *temp;
4780 int max_len;
4781 struct dfs_info3_param *node = (*target_nodes)+i;
4782
Steve French0e0d2cf2009-05-01 05:27:32 +00004783 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004784 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004785 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4786 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004787 if (tmp == NULL) {
4788 rc = -ENOMEM;
4789 goto parse_DFS_referrals_exit;
4790 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004791 cifsConvertToUTF16((__le16 *) tmp, searchName,
4792 PATH_MAX, nls_codepage, remap);
4793 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004794 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004795 nls_codepage);
4796 kfree(tmp);
4797 } else
4798 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4799
Igor Mammedovfec45852008-05-16 13:06:30 +04004800 node->server_type = le16_to_cpu(ref->ServerType);
4801 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4802
4803 /* copy DfsPath */
4804 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4805 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004806 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4807 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004808 if (!node->path_name) {
4809 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004810 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004811 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004812
4813 /* copy link target UNC */
4814 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4815 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004816 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4817 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004818 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004819 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004820 goto parse_DFS_referrals_exit;
4821 }
4822
4823 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004824 }
4825
Steve Frencha1fe78f2008-05-16 18:48:38 +00004826parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004827 if (rc) {
4828 free_dfs_info_array(*target_nodes, *num_of_nodes);
4829 *target_nodes = NULL;
4830 *num_of_nodes = 0;
4831 }
4832 return rc;
4833}
4834
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004836CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004837 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004838 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004839 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840{
4841/* TRANS2_GET_DFS_REFERRAL */
4842 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4843 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 int rc = 0;
4845 int bytes_returned;
4846 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004848 *num_of_nodes = 0;
4849 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850
Joe Perchesf96637b2013-05-04 22:12:25 -05004851 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 if (ses == NULL)
4853 return -ENODEV;
4854getDFSRetry:
4855 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4856 (void **) &pSMBr);
4857 if (rc)
4858 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004859
4860 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004861 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004862 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 pSMB->hdr.Tid = ses->ipc_tid;
4864 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004865 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004867 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869
4870 if (ses->capabilities & CAP_UNICODE) {
4871 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4872 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004873 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004874 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004875 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 name_len++; /* trailing null */
4877 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004878 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004879 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004881 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 }
4883
Jeff Layton38d77c52013-05-26 07:01:00 -04004884 if (ses->server && ses->server->sign)
4885 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004886
Steve French50c2f752007-07-13 00:33:32 +00004887 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004888
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 params = 2 /* level */ + name_len /*includes null */ ;
4890 pSMB->TotalDataCount = 0;
4891 pSMB->DataCount = 0;
4892 pSMB->DataOffset = 0;
4893 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004894 /* BB find exact max SMB PDU from sess structure BB */
4895 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 pSMB->MaxSetupCount = 0;
4897 pSMB->Reserved = 0;
4898 pSMB->Flags = 0;
4899 pSMB->Timeout = 0;
4900 pSMB->Reserved2 = 0;
4901 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004902 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 pSMB->SetupCount = 1;
4904 pSMB->Reserved3 = 0;
4905 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4906 byte_count = params + 3 /* pad */ ;
4907 pSMB->ParameterCount = cpu_to_le16(params);
4908 pSMB->TotalParameterCount = pSMB->ParameterCount;
4909 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004910 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 pSMB->ByteCount = cpu_to_le16(byte_count);
4912
4913 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4915 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004916 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004917 goto GetDFSRefExit;
4918 }
4919 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004921 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004922 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004923 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004924 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004926
Joe Perchesf96637b2013-05-04 22:12:25 -05004927 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4928 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004929
4930 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004931 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004932 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004933 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004934
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004936 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937
4938 if (rc == -EAGAIN)
4939 goto getDFSRetry;
4940
4941 return rc;
4942}
4943
Steve French20962432005-09-21 22:05:57 -07004944/* Query File System Info such as free space to old servers such as Win 9x */
4945int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004946SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4947 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004948{
4949/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4950 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4951 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4952 FILE_SYSTEM_ALLOC_INFO *response_data;
4953 int rc = 0;
4954 int bytes_returned = 0;
4955 __u16 params, byte_count;
4956
Joe Perchesf96637b2013-05-04 22:12:25 -05004957 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004958oldQFSInfoRetry:
4959 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4960 (void **) &pSMBr);
4961 if (rc)
4962 return rc;
Steve French20962432005-09-21 22:05:57 -07004963
4964 params = 2; /* level */
4965 pSMB->TotalDataCount = 0;
4966 pSMB->MaxParameterCount = cpu_to_le16(2);
4967 pSMB->MaxDataCount = cpu_to_le16(1000);
4968 pSMB->MaxSetupCount = 0;
4969 pSMB->Reserved = 0;
4970 pSMB->Flags = 0;
4971 pSMB->Timeout = 0;
4972 pSMB->Reserved2 = 0;
4973 byte_count = params + 1 /* pad */ ;
4974 pSMB->TotalParameterCount = cpu_to_le16(params);
4975 pSMB->ParameterCount = pSMB->TotalParameterCount;
4976 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4977 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4978 pSMB->DataCount = 0;
4979 pSMB->DataOffset = 0;
4980 pSMB->SetupCount = 1;
4981 pSMB->Reserved3 = 0;
4982 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4983 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004984 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004985 pSMB->ByteCount = cpu_to_le16(byte_count);
4986
4987 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4988 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4989 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004990 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004991 } else { /* decode response */
4992 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4993
Jeff Layton820a8032011-05-04 08:05:26 -04004994 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004995 rc = -EIO; /* bad smb */
4996 else {
4997 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004998 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004999 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005000
Steve French50c2f752007-07-13 00:33:32 +00005001 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005002 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5003 FSData->f_bsize =
5004 le16_to_cpu(response_data->BytesPerSector) *
5005 le32_to_cpu(response_data->
5006 SectorsPerAllocationUnit);
5007 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005008 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005009 FSData->f_bfree = FSData->f_bavail =
5010 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005011 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5012 (unsigned long long)FSData->f_blocks,
5013 (unsigned long long)FSData->f_bfree,
5014 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005015 }
5016 }
5017 cifs_buf_release(pSMB);
5018
5019 if (rc == -EAGAIN)
5020 goto oldQFSInfoRetry;
5021
5022 return rc;
5023}
5024
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005026CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5027 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028{
5029/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5030 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5031 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5032 FILE_SYSTEM_INFO *response_data;
5033 int rc = 0;
5034 int bytes_returned = 0;
5035 __u16 params, byte_count;
5036
Joe Perchesf96637b2013-05-04 22:12:25 -05005037 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038QFSInfoRetry:
5039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5040 (void **) &pSMBr);
5041 if (rc)
5042 return rc;
5043
5044 params = 2; /* level */
5045 pSMB->TotalDataCount = 0;
5046 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005047 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 pSMB->MaxSetupCount = 0;
5049 pSMB->Reserved = 0;
5050 pSMB->Flags = 0;
5051 pSMB->Timeout = 0;
5052 pSMB->Reserved2 = 0;
5053 byte_count = params + 1 /* pad */ ;
5054 pSMB->TotalParameterCount = cpu_to_le16(params);
5055 pSMB->ParameterCount = pSMB->TotalParameterCount;
5056 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005057 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 pSMB->DataCount = 0;
5059 pSMB->DataOffset = 0;
5060 pSMB->SetupCount = 1;
5061 pSMB->Reserved3 = 0;
5062 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5063 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005064 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 pSMB->ByteCount = cpu_to_le16(byte_count);
5066
5067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5069 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005070 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005072 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073
Jeff Layton820a8032011-05-04 08:05:26 -04005074 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 rc = -EIO; /* bad smb */
5076 else {
5077 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078
5079 response_data =
5080 (FILE_SYSTEM_INFO
5081 *) (((char *) &pSMBr->hdr.Protocol) +
5082 data_offset);
5083 FSData->f_bsize =
5084 le32_to_cpu(response_data->BytesPerSector) *
5085 le32_to_cpu(response_data->
5086 SectorsPerAllocationUnit);
5087 FSData->f_blocks =
5088 le64_to_cpu(response_data->TotalAllocationUnits);
5089 FSData->f_bfree = FSData->f_bavail =
5090 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005091 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5092 (unsigned long long)FSData->f_blocks,
5093 (unsigned long long)FSData->f_bfree,
5094 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 }
5096 }
5097 cifs_buf_release(pSMB);
5098
5099 if (rc == -EAGAIN)
5100 goto QFSInfoRetry;
5101
5102 return rc;
5103}
5104
5105int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005106CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107{
5108/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5109 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5110 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5111 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5112 int rc = 0;
5113 int bytes_returned = 0;
5114 __u16 params, byte_count;
5115
Joe Perchesf96637b2013-05-04 22:12:25 -05005116 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117QFSAttributeRetry:
5118 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5119 (void **) &pSMBr);
5120 if (rc)
5121 return rc;
5122
5123 params = 2; /* level */
5124 pSMB->TotalDataCount = 0;
5125 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005126 /* BB find exact max SMB PDU from sess structure BB */
5127 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 pSMB->MaxSetupCount = 0;
5129 pSMB->Reserved = 0;
5130 pSMB->Flags = 0;
5131 pSMB->Timeout = 0;
5132 pSMB->Reserved2 = 0;
5133 byte_count = params + 1 /* pad */ ;
5134 pSMB->TotalParameterCount = cpu_to_le16(params);
5135 pSMB->ParameterCount = pSMB->TotalParameterCount;
5136 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005137 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 pSMB->DataCount = 0;
5139 pSMB->DataOffset = 0;
5140 pSMB->SetupCount = 1;
5141 pSMB->Reserved3 = 0;
5142 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5143 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005144 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 pSMB->ByteCount = cpu_to_le16(byte_count);
5146
5147 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5148 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5149 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005150 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 } else { /* decode response */
5152 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5153
Jeff Layton820a8032011-05-04 08:05:26 -04005154 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005155 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 rc = -EIO; /* bad smb */
5157 } else {
5158 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5159 response_data =
5160 (FILE_SYSTEM_ATTRIBUTE_INFO
5161 *) (((char *) &pSMBr->hdr.Protocol) +
5162 data_offset);
5163 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005164 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 }
5166 }
5167 cifs_buf_release(pSMB);
5168
5169 if (rc == -EAGAIN)
5170 goto QFSAttributeRetry;
5171
5172 return rc;
5173}
5174
5175int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005176CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177{
5178/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5179 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5180 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5181 FILE_SYSTEM_DEVICE_INFO *response_data;
5182 int rc = 0;
5183 int bytes_returned = 0;
5184 __u16 params, byte_count;
5185
Joe Perchesf96637b2013-05-04 22:12:25 -05005186 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187QFSDeviceRetry:
5188 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5189 (void **) &pSMBr);
5190 if (rc)
5191 return rc;
5192
5193 params = 2; /* level */
5194 pSMB->TotalDataCount = 0;
5195 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005196 /* BB find exact max SMB PDU from sess structure BB */
5197 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 pSMB->MaxSetupCount = 0;
5199 pSMB->Reserved = 0;
5200 pSMB->Flags = 0;
5201 pSMB->Timeout = 0;
5202 pSMB->Reserved2 = 0;
5203 byte_count = params + 1 /* pad */ ;
5204 pSMB->TotalParameterCount = cpu_to_le16(params);
5205 pSMB->ParameterCount = pSMB->TotalParameterCount;
5206 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005207 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208
5209 pSMB->DataCount = 0;
5210 pSMB->DataOffset = 0;
5211 pSMB->SetupCount = 1;
5212 pSMB->Reserved3 = 0;
5213 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5214 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005215 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 pSMB->ByteCount = cpu_to_le16(byte_count);
5217
5218 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5219 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5220 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005221 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 } else { /* decode response */
5223 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5224
Jeff Layton820a8032011-05-04 08:05:26 -04005225 if (rc || get_bcc(&pSMBr->hdr) <
5226 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 rc = -EIO; /* bad smb */
5228 else {
5229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5230 response_data =
Steve French737b7582005-04-28 22:41:06 -07005231 (FILE_SYSTEM_DEVICE_INFO *)
5232 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 data_offset);
5234 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005235 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 }
5237 }
5238 cifs_buf_release(pSMB);
5239
5240 if (rc == -EAGAIN)
5241 goto QFSDeviceRetry;
5242
5243 return rc;
5244}
5245
5246int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005247CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248{
5249/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5250 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5251 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5252 FILE_SYSTEM_UNIX_INFO *response_data;
5253 int rc = 0;
5254 int bytes_returned = 0;
5255 __u16 params, byte_count;
5256
Joe Perchesf96637b2013-05-04 22:12:25 -05005257 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005259 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5260 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 if (rc)
5262 return rc;
5263
5264 params = 2; /* level */
5265 pSMB->TotalDataCount = 0;
5266 pSMB->DataCount = 0;
5267 pSMB->DataOffset = 0;
5268 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005269 /* BB find exact max SMB PDU from sess structure BB */
5270 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 pSMB->MaxSetupCount = 0;
5272 pSMB->Reserved = 0;
5273 pSMB->Flags = 0;
5274 pSMB->Timeout = 0;
5275 pSMB->Reserved2 = 0;
5276 byte_count = params + 1 /* pad */ ;
5277 pSMB->ParameterCount = cpu_to_le16(params);
5278 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005279 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5280 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 pSMB->SetupCount = 1;
5282 pSMB->Reserved3 = 0;
5283 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5284 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005285 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 pSMB->ByteCount = cpu_to_le16(byte_count);
5287
5288 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5289 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5290 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005291 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 } else { /* decode response */
5293 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5294
Jeff Layton820a8032011-05-04 08:05:26 -04005295 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 rc = -EIO; /* bad smb */
5297 } else {
5298 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5299 response_data =
5300 (FILE_SYSTEM_UNIX_INFO
5301 *) (((char *) &pSMBr->hdr.Protocol) +
5302 data_offset);
5303 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005304 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 }
5306 }
5307 cifs_buf_release(pSMB);
5308
5309 if (rc == -EAGAIN)
5310 goto QFSUnixRetry;
5311
5312
5313 return rc;
5314}
5315
Jeremy Allisonac670552005-06-22 17:26:35 -07005316int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005317CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005318{
5319/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5320 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5321 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5322 int rc = 0;
5323 int bytes_returned = 0;
5324 __u16 params, param_offset, offset, byte_count;
5325
Joe Perchesf96637b2013-05-04 22:12:25 -05005326 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005327SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005328 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005329 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5330 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005331 if (rc)
5332 return rc;
5333
5334 params = 4; /* 2 bytes zero followed by info level. */
5335 pSMB->MaxSetupCount = 0;
5336 pSMB->Reserved = 0;
5337 pSMB->Flags = 0;
5338 pSMB->Timeout = 0;
5339 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005340 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5341 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005342 offset = param_offset + params;
5343
5344 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005345 /* BB find exact max SMB PDU from sess structure BB */
5346 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005347 pSMB->SetupCount = 1;
5348 pSMB->Reserved3 = 0;
5349 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5350 byte_count = 1 /* pad */ + params + 12;
5351
5352 pSMB->DataCount = cpu_to_le16(12);
5353 pSMB->ParameterCount = cpu_to_le16(params);
5354 pSMB->TotalDataCount = pSMB->DataCount;
5355 pSMB->TotalParameterCount = pSMB->ParameterCount;
5356 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5357 pSMB->DataOffset = cpu_to_le16(offset);
5358
5359 /* Params. */
5360 pSMB->FileNum = 0;
5361 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5362
5363 /* Data. */
5364 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5365 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5366 pSMB->ClientUnixCap = cpu_to_le64(cap);
5367
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005368 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005369 pSMB->ByteCount = cpu_to_le16(byte_count);
5370
5371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5372 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5373 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005374 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005375 } else { /* decode response */
5376 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005377 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005378 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005379 }
5380 cifs_buf_release(pSMB);
5381
5382 if (rc == -EAGAIN)
5383 goto SETFSUnixRetry;
5384
5385 return rc;
5386}
5387
5388
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389
5390int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005391CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005392 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393{
5394/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5395 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5396 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5397 FILE_SYSTEM_POSIX_INFO *response_data;
5398 int rc = 0;
5399 int bytes_returned = 0;
5400 __u16 params, byte_count;
5401
Joe Perchesf96637b2013-05-04 22:12:25 -05005402 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403QFSPosixRetry:
5404 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5405 (void **) &pSMBr);
5406 if (rc)
5407 return rc;
5408
5409 params = 2; /* level */
5410 pSMB->TotalDataCount = 0;
5411 pSMB->DataCount = 0;
5412 pSMB->DataOffset = 0;
5413 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005414 /* BB find exact max SMB PDU from sess structure BB */
5415 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 pSMB->MaxSetupCount = 0;
5417 pSMB->Reserved = 0;
5418 pSMB->Flags = 0;
5419 pSMB->Timeout = 0;
5420 pSMB->Reserved2 = 0;
5421 byte_count = params + 1 /* pad */ ;
5422 pSMB->ParameterCount = cpu_to_le16(params);
5423 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005424 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5425 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 pSMB->SetupCount = 1;
5427 pSMB->Reserved3 = 0;
5428 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5429 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005430 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 pSMB->ByteCount = cpu_to_le16(byte_count);
5432
5433 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5434 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5435 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005436 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 } else { /* decode response */
5438 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5439
Jeff Layton820a8032011-05-04 08:05:26 -04005440 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 rc = -EIO; /* bad smb */
5442 } else {
5443 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5444 response_data =
5445 (FILE_SYSTEM_POSIX_INFO
5446 *) (((char *) &pSMBr->hdr.Protocol) +
5447 data_offset);
5448 FSData->f_bsize =
5449 le32_to_cpu(response_data->BlockSize);
5450 FSData->f_blocks =
5451 le64_to_cpu(response_data->TotalBlocks);
5452 FSData->f_bfree =
5453 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005454 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 FSData->f_bavail = FSData->f_bfree;
5456 } else {
5457 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005458 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 }
Steve French790fe572007-07-07 19:25:05 +00005460 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005462 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005463 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005465 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 }
5467 }
5468 cifs_buf_release(pSMB);
5469
5470 if (rc == -EAGAIN)
5471 goto QFSPosixRetry;
5472
5473 return rc;
5474}
5475
5476
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005477/*
5478 * We can not use write of zero bytes trick to set file size due to need for
5479 * large file support. Also note that this SetPathInfo is preferred to
5480 * SetFileInfo based method in next routine which is only needed to work around
5481 * a sharing violation bugin Samba which this routine can run into.
5482 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005484CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005485 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5486 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487{
5488 struct smb_com_transaction2_spi_req *pSMB = NULL;
5489 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5490 struct file_end_of_file_info *parm_data;
5491 int name_len;
5492 int rc = 0;
5493 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005494 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5495
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 __u16 params, byte_count, data_count, param_offset, offset;
5497
Joe Perchesf96637b2013-05-04 22:12:25 -05005498 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499SetEOFRetry:
5500 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5501 (void **) &pSMBr);
5502 if (rc)
5503 return rc;
5504
5505 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5506 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005507 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5508 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 name_len++; /* trailing null */
5510 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005511 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005512 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005514 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 }
5516 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005517 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005519 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 pSMB->MaxSetupCount = 0;
5521 pSMB->Reserved = 0;
5522 pSMB->Flags = 0;
5523 pSMB->Timeout = 0;
5524 pSMB->Reserved2 = 0;
5525 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005526 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005528 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005529 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5530 pSMB->InformationLevel =
5531 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5532 else
5533 pSMB->InformationLevel =
5534 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5535 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5537 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005538 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 else
5540 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005541 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 }
5543
5544 parm_data =
5545 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5546 offset);
5547 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5548 pSMB->DataOffset = cpu_to_le16(offset);
5549 pSMB->SetupCount = 1;
5550 pSMB->Reserved3 = 0;
5551 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5552 byte_count = 3 /* pad */ + params + data_count;
5553 pSMB->DataCount = cpu_to_le16(data_count);
5554 pSMB->TotalDataCount = pSMB->DataCount;
5555 pSMB->ParameterCount = cpu_to_le16(params);
5556 pSMB->TotalParameterCount = pSMB->ParameterCount;
5557 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005558 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 parm_data->FileSize = cpu_to_le64(size);
5560 pSMB->ByteCount = cpu_to_le16(byte_count);
5561 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5562 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005563 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005564 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565
5566 cifs_buf_release(pSMB);
5567
5568 if (rc == -EAGAIN)
5569 goto SetEOFRetry;
5570
5571 return rc;
5572}
5573
5574int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005575CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5576 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577{
5578 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 struct file_end_of_file_info *parm_data;
5580 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 __u16 params, param_offset, offset, byte_count, count;
5582
Joe Perchesf96637b2013-05-04 22:12:25 -05005583 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5584 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005585 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5586
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 if (rc)
5588 return rc;
5589
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005590 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5591 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005592
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 params = 6;
5594 pSMB->MaxSetupCount = 0;
5595 pSMB->Reserved = 0;
5596 pSMB->Flags = 0;
5597 pSMB->Timeout = 0;
5598 pSMB->Reserved2 = 0;
5599 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5600 offset = param_offset + params;
5601
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 count = sizeof(struct file_end_of_file_info);
5603 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005604 /* BB find exact max SMB PDU from sess structure BB */
5605 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 pSMB->SetupCount = 1;
5607 pSMB->Reserved3 = 0;
5608 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5609 byte_count = 3 /* pad */ + params + count;
5610 pSMB->DataCount = cpu_to_le16(count);
5611 pSMB->ParameterCount = cpu_to_le16(params);
5612 pSMB->TotalDataCount = pSMB->DataCount;
5613 pSMB->TotalParameterCount = pSMB->ParameterCount;
5614 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5615 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005616 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5617 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 pSMB->DataOffset = cpu_to_le16(offset);
5619 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005620 pSMB->Fid = cfile->fid.netfid;
5621 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5623 pSMB->InformationLevel =
5624 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5625 else
5626 pSMB->InformationLevel =
5627 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005628 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5630 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005631 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 else
5633 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005634 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 }
5636 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005637 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005639 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005641 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5642 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 }
5644
Steve French50c2f752007-07-13 00:33:32 +00005645 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 since file handle passed in no longer valid */
5647
5648 return rc;
5649}
5650
Steve French50c2f752007-07-13 00:33:32 +00005651/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 an open handle, rather than by pathname - this is awkward due to
5653 potential access conflicts on the open, but it is unavoidable for these
5654 old servers since the only other choice is to go from 100 nanosecond DCE
5655 time and resort to the original setpathinfo level which takes the ancient
5656 DOS time format with 2 second granularity */
5657int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005658CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005659 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660{
5661 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 char *data_offset;
5663 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 __u16 params, param_offset, offset, byte_count, count;
5665
Joe Perchesf96637b2013-05-04 22:12:25 -05005666 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005667 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5668
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 if (rc)
5670 return rc;
5671
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005672 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5673 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005674
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 params = 6;
5676 pSMB->MaxSetupCount = 0;
5677 pSMB->Reserved = 0;
5678 pSMB->Flags = 0;
5679 pSMB->Timeout = 0;
5680 pSMB->Reserved2 = 0;
5681 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5682 offset = param_offset + params;
5683
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005684 data_offset = (char *)pSMB +
5685 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686
Steve French26f57362007-08-30 22:09:15 +00005687 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005689 /* BB find max SMB PDU from sess */
5690 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 pSMB->SetupCount = 1;
5692 pSMB->Reserved3 = 0;
5693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5694 byte_count = 3 /* pad */ + params + count;
5695 pSMB->DataCount = cpu_to_le16(count);
5696 pSMB->ParameterCount = cpu_to_le16(params);
5697 pSMB->TotalDataCount = pSMB->DataCount;
5698 pSMB->TotalParameterCount = pSMB->ParameterCount;
5699 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5700 pSMB->DataOffset = cpu_to_le16(offset);
5701 pSMB->Fid = fid;
5702 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5703 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5704 else
5705 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5706 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005707 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005709 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005710 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005711 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005712 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5713 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714
Steve French50c2f752007-07-13 00:33:32 +00005715 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 since file handle passed in no longer valid */
5717
5718 return rc;
5719}
5720
Jeff Layton6d22f092008-09-23 11:48:35 -04005721int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005722CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005723 bool delete_file, __u16 fid, __u32 pid_of_opener)
5724{
5725 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5726 char *data_offset;
5727 int rc = 0;
5728 __u16 params, param_offset, offset, byte_count, count;
5729
Joe Perchesf96637b2013-05-04 22:12:25 -05005730 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005731 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5732
5733 if (rc)
5734 return rc;
5735
5736 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5737 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5738
5739 params = 6;
5740 pSMB->MaxSetupCount = 0;
5741 pSMB->Reserved = 0;
5742 pSMB->Flags = 0;
5743 pSMB->Timeout = 0;
5744 pSMB->Reserved2 = 0;
5745 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5746 offset = param_offset + params;
5747
5748 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5749
5750 count = 1;
5751 pSMB->MaxParameterCount = cpu_to_le16(2);
5752 /* BB find max SMB PDU from sess */
5753 pSMB->MaxDataCount = cpu_to_le16(1000);
5754 pSMB->SetupCount = 1;
5755 pSMB->Reserved3 = 0;
5756 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5757 byte_count = 3 /* pad */ + params + count;
5758 pSMB->DataCount = cpu_to_le16(count);
5759 pSMB->ParameterCount = cpu_to_le16(params);
5760 pSMB->TotalDataCount = pSMB->DataCount;
5761 pSMB->TotalParameterCount = pSMB->ParameterCount;
5762 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5763 pSMB->DataOffset = cpu_to_le16(offset);
5764 pSMB->Fid = fid;
5765 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5766 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005767 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005768 pSMB->ByteCount = cpu_to_le16(byte_count);
5769 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005770 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005771 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005772 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005773
5774 return rc;
5775}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776
5777int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005778CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005779 const char *fileName, const FILE_BASIC_INFO *data,
5780 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781{
5782 TRANSACTION2_SPI_REQ *pSMB = NULL;
5783 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5784 int name_len;
5785 int rc = 0;
5786 int bytes_returned = 0;
5787 char *data_offset;
5788 __u16 params, param_offset, offset, byte_count, count;
5789
Joe Perchesf96637b2013-05-04 22:12:25 -05005790 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
5792SetTimesRetry:
5793 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5794 (void **) &pSMBr);
5795 if (rc)
5796 return rc;
5797
5798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5799 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005800 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5801 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 name_len++; /* trailing null */
5803 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005804 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805 name_len = strnlen(fileName, PATH_MAX);
5806 name_len++; /* trailing null */
5807 strncpy(pSMB->FileName, fileName, name_len);
5808 }
5809
5810 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005811 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005813 /* BB find max SMB PDU from sess structure BB */
5814 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 pSMB->MaxSetupCount = 0;
5816 pSMB->Reserved = 0;
5817 pSMB->Flags = 0;
5818 pSMB->Timeout = 0;
5819 pSMB->Reserved2 = 0;
5820 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005821 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 offset = param_offset + params;
5823 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5824 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5825 pSMB->DataOffset = cpu_to_le16(offset);
5826 pSMB->SetupCount = 1;
5827 pSMB->Reserved3 = 0;
5828 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5829 byte_count = 3 /* pad */ + params + count;
5830
5831 pSMB->DataCount = cpu_to_le16(count);
5832 pSMB->ParameterCount = cpu_to_le16(params);
5833 pSMB->TotalDataCount = pSMB->DataCount;
5834 pSMB->TotalParameterCount = pSMB->ParameterCount;
5835 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5836 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5837 else
5838 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5839 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005840 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005841 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842 pSMB->ByteCount = cpu_to_le16(byte_count);
5843 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5844 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005845 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005846 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
5848 cifs_buf_release(pSMB);
5849
5850 if (rc == -EAGAIN)
5851 goto SetTimesRetry;
5852
5853 return rc;
5854}
5855
5856/* Can not be used to set time stamps yet (due to old DOS time format) */
5857/* Can be used to set attributes */
5858#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5859 handling it anyway and NT4 was what we thought it would be needed for
5860 Do not delete it until we prove whether needed for Win9x though */
5861int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005862CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863 __u16 dos_attrs, const struct nls_table *nls_codepage)
5864{
5865 SETATTR_REQ *pSMB = NULL;
5866 SETATTR_RSP *pSMBr = NULL;
5867 int rc = 0;
5868 int bytes_returned;
5869 int name_len;
5870
Joe Perchesf96637b2013-05-04 22:12:25 -05005871 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872
5873SetAttrLgcyRetry:
5874 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5875 (void **) &pSMBr);
5876 if (rc)
5877 return rc;
5878
5879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5880 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005881 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5882 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883 name_len++; /* trailing null */
5884 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005885 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 name_len = strnlen(fileName, PATH_MAX);
5887 name_len++; /* trailing null */
5888 strncpy(pSMB->fileName, fileName, name_len);
5889 }
5890 pSMB->attr = cpu_to_le16(dos_attrs);
5891 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005892 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005896 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005897 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898
5899 cifs_buf_release(pSMB);
5900
5901 if (rc == -EAGAIN)
5902 goto SetAttrLgcyRetry;
5903
5904 return rc;
5905}
5906#endif /* temporarily unneeded SetAttr legacy function */
5907
Jeff Layton654cf142009-07-09 20:02:49 -04005908static void
5909cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5910 const struct cifs_unix_set_info_args *args)
5911{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005912 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005913 u64 mode = args->mode;
5914
Eric W. Biederman49418b22013-02-06 00:57:56 -08005915 if (uid_valid(args->uid))
5916 uid = from_kuid(&init_user_ns, args->uid);
5917 if (gid_valid(args->gid))
5918 gid = from_kgid(&init_user_ns, args->gid);
5919
Jeff Layton654cf142009-07-09 20:02:49 -04005920 /*
5921 * Samba server ignores set of file size to zero due to bugs in some
5922 * older clients, but we should be precise - we use SetFileSize to
5923 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005924 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005925 * zero instead of -1 here
5926 */
5927 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5928 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5929 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5930 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5931 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005932 data_offset->Uid = cpu_to_le64(uid);
5933 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005934 /* better to leave device as zero when it is */
5935 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5936 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5937 data_offset->Permissions = cpu_to_le64(mode);
5938
5939 if (S_ISREG(mode))
5940 data_offset->Type = cpu_to_le32(UNIX_FILE);
5941 else if (S_ISDIR(mode))
5942 data_offset->Type = cpu_to_le32(UNIX_DIR);
5943 else if (S_ISLNK(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5945 else if (S_ISCHR(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5947 else if (S_ISBLK(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5949 else if (S_ISFIFO(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5951 else if (S_ISSOCK(mode))
5952 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5953}
5954
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005956CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005957 const struct cifs_unix_set_info_args *args,
5958 u16 fid, u32 pid_of_opener)
5959{
5960 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005961 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005962 int rc = 0;
5963 u16 params, param_offset, offset, byte_count, count;
5964
Joe Perchesf96637b2013-05-04 22:12:25 -05005965 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005966 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5967
5968 if (rc)
5969 return rc;
5970
5971 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5972 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5973
5974 params = 6;
5975 pSMB->MaxSetupCount = 0;
5976 pSMB->Reserved = 0;
5977 pSMB->Flags = 0;
5978 pSMB->Timeout = 0;
5979 pSMB->Reserved2 = 0;
5980 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5981 offset = param_offset + params;
5982
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005983 data_offset = (char *)pSMB +
5984 offsetof(struct smb_hdr, Protocol) + offset;
5985
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005986 count = sizeof(FILE_UNIX_BASIC_INFO);
5987
5988 pSMB->MaxParameterCount = cpu_to_le16(2);
5989 /* BB find max SMB PDU from sess */
5990 pSMB->MaxDataCount = cpu_to_le16(1000);
5991 pSMB->SetupCount = 1;
5992 pSMB->Reserved3 = 0;
5993 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5994 byte_count = 3 /* pad */ + params + count;
5995 pSMB->DataCount = cpu_to_le16(count);
5996 pSMB->ParameterCount = cpu_to_le16(params);
5997 pSMB->TotalDataCount = pSMB->DataCount;
5998 pSMB->TotalParameterCount = pSMB->ParameterCount;
5999 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6000 pSMB->DataOffset = cpu_to_le16(offset);
6001 pSMB->Fid = fid;
6002 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6003 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006004 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006005 pSMB->ByteCount = cpu_to_le16(byte_count);
6006
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006007 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006008
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006009 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006010 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006011 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6012 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006013
6014 /* Note: On -EAGAIN error only caller can retry on handle based calls
6015 since file handle passed in no longer valid */
6016
6017 return rc;
6018}
6019
6020int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006021CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006022 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006023 const struct cifs_unix_set_info_args *args,
6024 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025{
6026 TRANSACTION2_SPI_REQ *pSMB = NULL;
6027 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6028 int name_len;
6029 int rc = 0;
6030 int bytes_returned = 0;
6031 FILE_UNIX_BASIC_INFO *data_offset;
6032 __u16 params, param_offset, offset, count, byte_count;
6033
Joe Perchesf96637b2013-05-04 22:12:25 -05006034 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035setPermsRetry:
6036 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6037 (void **) &pSMBr);
6038 if (rc)
6039 return rc;
6040
6041 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6042 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006043 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006044 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 name_len++; /* trailing null */
6046 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006047 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006048 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006050 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051 }
6052
6053 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006054 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006056 /* BB find max SMB PDU from sess structure BB */
6057 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 pSMB->MaxSetupCount = 0;
6059 pSMB->Reserved = 0;
6060 pSMB->Flags = 0;
6061 pSMB->Timeout = 0;
6062 pSMB->Reserved2 = 0;
6063 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006064 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065 offset = param_offset + params;
6066 data_offset =
6067 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6068 offset);
6069 memset(data_offset, 0, count);
6070 pSMB->DataOffset = cpu_to_le16(offset);
6071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6072 pSMB->SetupCount = 1;
6073 pSMB->Reserved3 = 0;
6074 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6075 byte_count = 3 /* pad */ + params + count;
6076 pSMB->ParameterCount = cpu_to_le16(params);
6077 pSMB->DataCount = cpu_to_le16(count);
6078 pSMB->TotalParameterCount = pSMB->ParameterCount;
6079 pSMB->TotalDataCount = pSMB->DataCount;
6080 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6081 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006082 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006083
Jeff Layton654cf142009-07-09 20:02:49 -04006084 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085
6086 pSMB->ByteCount = cpu_to_le16(byte_count);
6087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6088 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006089 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006090 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091
Steve French0d817bc2008-05-22 02:02:03 +00006092 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 if (rc == -EAGAIN)
6094 goto setPermsRetry;
6095 return rc;
6096}
6097
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006099/*
6100 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6101 * function used by listxattr and getxattr type calls. When ea_name is set,
6102 * it looks for that attribute name and stuffs that value into the EAData
6103 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6104 * buffer. In both cases, the return value is either the length of the
6105 * resulting data or a negative error code. If EAData is a NULL pointer then
6106 * the data isn't copied to it, but the length is returned.
6107 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006109CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006110 const unsigned char *searchName, const unsigned char *ea_name,
6111 char *EAData, size_t buf_size,
6112 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113{
6114 /* BB assumes one setup word */
6115 TRANSACTION2_QPI_REQ *pSMB = NULL;
6116 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6117 int rc = 0;
6118 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006119 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006120 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006121 struct fea *temp_fea;
6122 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006123 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006125 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126
Joe Perchesf96637b2013-05-04 22:12:25 -05006127 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128QAllEAsRetry:
6129 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6130 (void **) &pSMBr);
6131 if (rc)
6132 return rc;
6133
6134 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006135 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006136 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6137 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006138 list_len++; /* trailing null */
6139 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006141 list_len = strnlen(searchName, PATH_MAX);
6142 list_len++; /* trailing null */
6143 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144 }
6145
Jeff Layton6e462b92010-02-10 16:18:26 -05006146 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 pSMB->TotalDataCount = 0;
6148 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006149 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006150 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 pSMB->MaxSetupCount = 0;
6152 pSMB->Reserved = 0;
6153 pSMB->Flags = 0;
6154 pSMB->Timeout = 0;
6155 pSMB->Reserved2 = 0;
6156 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006157 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 pSMB->DataCount = 0;
6159 pSMB->DataOffset = 0;
6160 pSMB->SetupCount = 1;
6161 pSMB->Reserved3 = 0;
6162 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6163 byte_count = params + 1 /* pad */ ;
6164 pSMB->TotalParameterCount = cpu_to_le16(params);
6165 pSMB->ParameterCount = pSMB->TotalParameterCount;
6166 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6167 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006168 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006169 pSMB->ByteCount = cpu_to_le16(byte_count);
6170
6171 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6172 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6173 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006174 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006175 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006177
6178
6179 /* BB also check enough total bytes returned */
6180 /* BB we need to improve the validity checking
6181 of these trans2 responses */
6182
6183 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006184 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006185 rc = -EIO; /* bad smb */
6186 goto QAllEAsOut;
6187 }
6188
6189 /* check that length of list is not more than bcc */
6190 /* check that each entry does not go beyond length
6191 of list */
6192 /* check that each element of each entry does not
6193 go beyond end of list */
6194 /* validate_trans2_offsets() */
6195 /* BB check if start of smb + data_offset > &bcc+ bcc */
6196
6197 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6198 ea_response_data = (struct fealist *)
6199 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6200
Jeff Layton6e462b92010-02-10 16:18:26 -05006201 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006202 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006203 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006204 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006205 goto QAllEAsOut;
6206 }
6207
Jeff Layton0cd126b2010-02-10 16:18:26 -05006208 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006209 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006210 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006211 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006212 rc = -EIO;
6213 goto QAllEAsOut;
6214 }
6215
Jeff Laytonf0d38682010-02-10 16:18:26 -05006216 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006217 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006218 temp_fea = ea_response_data->list;
6219 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006220 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006221 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006222 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006223
Jeff Layton6e462b92010-02-10 16:18:26 -05006224 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006225 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006226 /* make sure we can read name_len and value_len */
6227 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006228 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006229 rc = -EIO;
6230 goto QAllEAsOut;
6231 }
6232
6233 name_len = temp_fea->name_len;
6234 value_len = le16_to_cpu(temp_fea->value_len);
6235 list_len -= name_len + 1 + value_len;
6236 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006237 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006238 rc = -EIO;
6239 goto QAllEAsOut;
6240 }
6241
Jeff Layton31c05192010-02-10 16:18:26 -05006242 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006243 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006244 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006245 temp_ptr += name_len + 1;
6246 rc = value_len;
6247 if (buf_size == 0)
6248 goto QAllEAsOut;
6249 if ((size_t)value_len > buf_size) {
6250 rc = -ERANGE;
6251 goto QAllEAsOut;
6252 }
6253 memcpy(EAData, temp_ptr, value_len);
6254 goto QAllEAsOut;
6255 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006256 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006257 /* account for prefix user. and trailing null */
6258 rc += (5 + 1 + name_len);
6259 if (rc < (int) buf_size) {
6260 memcpy(EAData, "user.", 5);
6261 EAData += 5;
6262 memcpy(EAData, temp_ptr, name_len);
6263 EAData += name_len;
6264 /* null terminate name */
6265 *EAData = 0;
6266 ++EAData;
6267 } else if (buf_size == 0) {
6268 /* skip copy - calc size only */
6269 } else {
6270 /* stop before overrun buffer */
6271 rc = -ERANGE;
6272 break;
6273 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006274 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006275 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006276 temp_fea = (struct fea *)temp_ptr;
6277 }
6278
Jeff Layton31c05192010-02-10 16:18:26 -05006279 /* didn't find the named attribute */
6280 if (ea_name)
6281 rc = -ENODATA;
6282
Jeff Laytonf0d38682010-02-10 16:18:26 -05006283QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006284 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 if (rc == -EAGAIN)
6286 goto QAllEAsRetry;
6287
6288 return (ssize_t)rc;
6289}
6290
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006292CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6293 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006294 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6295 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296{
6297 struct smb_com_transaction2_spi_req *pSMB = NULL;
6298 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6299 struct fealist *parm_data;
6300 int name_len;
6301 int rc = 0;
6302 int bytes_returned = 0;
6303 __u16 params, param_offset, byte_count, offset, count;
6304
Joe Perchesf96637b2013-05-04 22:12:25 -05006305 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306SetEARetry:
6307 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6308 (void **) &pSMBr);
6309 if (rc)
6310 return rc;
6311
6312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6313 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006314 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6315 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 name_len++; /* trailing null */
6317 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006318 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 name_len = strnlen(fileName, PATH_MAX);
6320 name_len++; /* trailing null */
6321 strncpy(pSMB->FileName, fileName, name_len);
6322 }
6323
6324 params = 6 + name_len;
6325
6326 /* done calculating parms using name_len of file name,
6327 now use name_len to calculate length of ea name
6328 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006329 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 name_len = 0;
6331 else
Steve French50c2f752007-07-13 00:33:32 +00006332 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006334 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006336 /* BB find max SMB PDU from sess */
6337 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 pSMB->MaxSetupCount = 0;
6339 pSMB->Reserved = 0;
6340 pSMB->Flags = 0;
6341 pSMB->Timeout = 0;
6342 pSMB->Reserved2 = 0;
6343 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006344 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345 offset = param_offset + params;
6346 pSMB->InformationLevel =
6347 cpu_to_le16(SMB_SET_FILE_EA);
6348
6349 parm_data =
6350 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6351 offset);
6352 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6353 pSMB->DataOffset = cpu_to_le16(offset);
6354 pSMB->SetupCount = 1;
6355 pSMB->Reserved3 = 0;
6356 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6357 byte_count = 3 /* pad */ + params + count;
6358 pSMB->DataCount = cpu_to_le16(count);
6359 parm_data->list_len = cpu_to_le32(count);
6360 parm_data->list[0].EA_flags = 0;
6361 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006362 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006364 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006365 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366 parm_data->list[0].name[name_len] = 0;
6367 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6368 /* caller ensures that ea_value_len is less than 64K but
6369 we need to ensure that it fits within the smb */
6370
Steve French50c2f752007-07-13 00:33:32 +00006371 /*BB add length check to see if it would fit in
6372 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006373 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6374 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006375 memcpy(parm_data->list[0].name+name_len+1,
6376 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377
6378 pSMB->TotalDataCount = pSMB->DataCount;
6379 pSMB->ParameterCount = cpu_to_le16(params);
6380 pSMB->TotalParameterCount = pSMB->ParameterCount;
6381 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006382 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 pSMB->ByteCount = cpu_to_le16(byte_count);
6384 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6385 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006386 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006387 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388
6389 cifs_buf_release(pSMB);
6390
6391 if (rc == -EAGAIN)
6392 goto SetEARetry;
6393
6394 return rc;
6395}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006396#endif
Steve French0eff0e22011-02-24 05:39:23 +00006397
6398#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6399/*
6400 * Years ago the kernel added a "dnotify" function for Samba server,
6401 * to allow network clients (such as Windows) to display updated
6402 * lists of files in directory listings automatically when
6403 * files are added by one user when another user has the
6404 * same directory open on their desktop. The Linux cifs kernel
6405 * client hooked into the kernel side of this interface for
6406 * the same reason, but ironically when the VFS moved from
6407 * "dnotify" to "inotify" it became harder to plug in Linux
6408 * network file system clients (the most obvious use case
6409 * for notify interfaces is when multiple users can update
6410 * the contents of the same directory - exactly what network
6411 * file systems can do) although the server (Samba) could
6412 * still use it. For the short term we leave the worker
6413 * function ifdeffed out (below) until inotify is fixed
6414 * in the VFS to make it easier to plug in network file
6415 * system clients. If inotify turns out to be permanently
6416 * incompatible for network fs clients, we could instead simply
6417 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6418 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006419int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006420 const int notify_subdirs, const __u16 netfid,
6421 __u32 filter, struct file *pfile, int multishot,
6422 const struct nls_table *nls_codepage)
6423{
6424 int rc = 0;
6425 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6426 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6427 struct dir_notify_req *dnotify_req;
6428 int bytes_returned;
6429
Joe Perchesf96637b2013-05-04 22:12:25 -05006430 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006431 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6432 (void **) &pSMBr);
6433 if (rc)
6434 return rc;
6435
6436 pSMB->TotalParameterCount = 0 ;
6437 pSMB->TotalDataCount = 0;
6438 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006439 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006440 pSMB->MaxSetupCount = 4;
6441 pSMB->Reserved = 0;
6442 pSMB->ParameterOffset = 0;
6443 pSMB->DataCount = 0;
6444 pSMB->DataOffset = 0;
6445 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6446 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6447 pSMB->ParameterCount = pSMB->TotalParameterCount;
6448 if (notify_subdirs)
6449 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6450 pSMB->Reserved2 = 0;
6451 pSMB->CompletionFilter = cpu_to_le32(filter);
6452 pSMB->Fid = netfid; /* file handle always le */
6453 pSMB->ByteCount = 0;
6454
6455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6456 (struct smb_hdr *)pSMBr, &bytes_returned,
6457 CIFS_ASYNC_OP);
6458 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006459 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006460 } else {
6461 /* Add file to outstanding requests */
6462 /* BB change to kmem cache alloc */
6463 dnotify_req = kmalloc(
6464 sizeof(struct dir_notify_req),
6465 GFP_KERNEL);
6466 if (dnotify_req) {
6467 dnotify_req->Pid = pSMB->hdr.Pid;
6468 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6469 dnotify_req->Mid = pSMB->hdr.Mid;
6470 dnotify_req->Tid = pSMB->hdr.Tid;
6471 dnotify_req->Uid = pSMB->hdr.Uid;
6472 dnotify_req->netfid = netfid;
6473 dnotify_req->pfile = pfile;
6474 dnotify_req->filter = filter;
6475 dnotify_req->multishot = multishot;
6476 spin_lock(&GlobalMid_Lock);
6477 list_add_tail(&dnotify_req->lhead,
6478 &GlobalDnotifyReqList);
6479 spin_unlock(&GlobalMid_Lock);
6480 } else
6481 rc = -ENOMEM;
6482 }
6483 cifs_buf_release(pSMB);
6484 return rc;
6485}
6486#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */