blob: 1a3776322c71ee990601d6be7b078a2800923b1c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_lock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Jeff Layton44772882010-10-15 15:34:03 -0400107 spin_unlock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500142 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500166 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 rc = cifs_setup_session(0, ses, nls_codepage);
184
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 goto out;
189 }
190
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400191 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500194 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
199 /*
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
202 */
203 atomic_inc(&tconInfoReconnectCount);
204
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208
209 /*
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
212 *
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 */
215
216out:
217 /*
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
220 */
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
228 }
229
230 unload_nls(nls_codepage);
231 return rc;
232}
233
Steve Frenchad7a2922008-02-07 23:25:02 +0000234/* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int
Steve French96daf2b2011-05-27 04:34:02 +0000238small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000239 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Jeff Laytonf5695992010-09-29 15:27:08 -0400241 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000244 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return rc;
246
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
251 }
252
Steve French63135e02007-07-17 17:34:02 +0000253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000254 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Steve French790fe572007-07-07 19:25:05 +0000256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700258
Jeff Laytonf5695992010-09-29 15:27:08 -0400259 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000260}
261
Steve French12b3b8f2006-02-09 21:12:47 +0000262int
Steve French50c2f752007-07-13 00:33:32 +0000263small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000264 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000265{
266 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000267 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000268
Steve French5815449d2006-02-14 01:36:20 +0000269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 return rc;
272
Steve French04fdabe2006-02-10 05:52:50 +0000273 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400274 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000277 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279
280 /* uid, tid can stay at zero as set in header assemble */
281
Steve French50c2f752007-07-13 00:33:32 +0000282 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000283 this function is used after 1st of session setup requests */
284
285 return rc;
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288/* If the return code is zero, this function must fill in request_buf pointer */
289static int
Steve French96daf2b2011-05-27 04:34:02 +0000290__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400291 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700310
Jeff Laytonf5695992010-09-29 15:27:08 -0400311 return 0;
312}
313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
318{
319 int rc;
320
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
324
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326}
327
328static int
Steve French96daf2b2011-05-27 04:34:02 +0000329smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400330 void **request_buf, void **response_buf)
331{
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
334
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Steve French50c2f752007-07-13 00:33:32 +0000338static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
354
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
357 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
362
363 return 0;
364vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Jeff Layton690c5222011-01-20 13:36:51 -0500369
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400370static int
371decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
372{
373 int rc = 0;
374 u16 count;
375 char *guid = pSMBr->u.extended_response.GUID;
376
377 count = get_bcc(&pSMBr->hdr);
378 if (count < SMB1_CLIENT_GUID_SIZE)
379 return -EIO;
380
381 spin_lock(&cifs_tcp_ses_lock);
382 if (server->srv_count > 1) {
383 spin_unlock(&cifs_tcp_ses_lock);
384 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
385 cifs_dbg(FYI, "server UID changed\n");
386 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
387 }
388 } else {
389 spin_unlock(&cifs_tcp_ses_lock);
390 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
391 }
392
393 if (count == SMB1_CLIENT_GUID_SIZE) {
394 server->secType = RawNTLMSSP;
395 } else {
396 count -= SMB1_CLIENT_GUID_SIZE;
397 rc = decode_negTokenInit(
398 pSMBr->u.extended_response.SecurityBlob, count, server);
399 if (rc != 1)
400 return -EINVAL;
401
402 /* Make sure server supports what we want to use */
403 switch(server->secType) {
404 case Kerberos:
405 if (!server->sec_kerberos && !server->sec_mskerberos)
406 return -EOPNOTSUPP;
407 break;
408 case RawNTLMSSP:
409 if (!server->sec_ntlmssp)
410 return -EOPNOTSUPP;
411 break;
412 default:
413 return -EOPNOTSUPP;
414 }
415 }
416
417 return 0;
418}
419
Jeff Layton9ddec562013-05-26 07:00:58 -0400420int
421cifs_enable_signing(struct TCP_Server_Info *server, unsigned int secFlags)
422{
423 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
424 /* MUST_SIGN already includes the MAY_SIGN FLAG
425 so if this is zero it means that signing is disabled */
426 cifs_dbg(FYI, "Signing disabled\n");
427 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
428 cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
429 return -EOPNOTSUPP;
430 }
431 server->sec_mode &=
432 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
433 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
434 /* signing required */
435 cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
436 if ((server->sec_mode &
437 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
438 cifs_dbg(VFS, "signing required but server lacks support\n");
439 return -EOPNOTSUPP;
440 } else
441 server->sec_mode |= SECMODE_SIGN_REQUIRED;
442 } else {
443 /* signing optional ie CIFSSEC_MAY_SIGN */
444 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
445 server->sec_mode &=
446 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
447 }
448
449 return 0;
450}
451
Jeff Layton2190eca2013-05-26 07:00:57 -0400452#ifdef CONFIG_CIFS_WEAK_PW_HASH
453static int
454decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
455 unsigned int secFlags)
456{
457 __s16 tmp;
458 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
459
460 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
461 return -EOPNOTSUPP;
462
463 if ((secFlags & CIFSSEC_MAY_LANMAN) || (secFlags & CIFSSEC_MAY_PLNTXT))
464 server->secType = LANMAN;
465 else {
466 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
467 return -EOPNOTSUPP;
468 }
469 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
470 server->maxReq = min_t(unsigned int,
471 le16_to_cpu(rsp->MaxMpxCount),
472 cifs_max_pending);
473 set_credits(server, server->maxReq);
474 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
475 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
476 /* even though we do not use raw we might as well set this
477 accurately, in case we ever find a need for it */
478 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
479 server->max_rw = 0xFF00;
480 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
481 } else {
482 server->max_rw = 0;/* do not need to use raw anyway */
483 server->capabilities = CAP_MPX_MODE;
484 }
485 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
486 if (tmp == -1) {
487 /* OS/2 often does not set timezone therefore
488 * we must use server time to calc time zone.
489 * Could deviate slightly from the right zone.
490 * Smallest defined timezone difference is 15 minutes
491 * (i.e. Nepal). Rounding up/down is done to match
492 * this requirement.
493 */
494 int val, seconds, remain, result;
495 struct timespec ts, utc;
496 utc = CURRENT_TIME;
497 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
498 rsp->SrvTime.Time, 0);
499 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
500 (int)ts.tv_sec, (int)utc.tv_sec,
501 (int)(utc.tv_sec - ts.tv_sec));
502 val = (int)(utc.tv_sec - ts.tv_sec);
503 seconds = abs(val);
504 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
505 remain = seconds % MIN_TZ_ADJ;
506 if (remain >= (MIN_TZ_ADJ / 2))
507 result += MIN_TZ_ADJ;
508 if (val < 0)
509 result = -result;
510 server->timeAdj = result;
511 } else {
512 server->timeAdj = (int)tmp;
513 server->timeAdj *= 60; /* also in seconds */
514 }
515 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
516
517
518 /* BB get server time for time conversions and add
519 code to use it and timezone since this is not UTC */
520
521 if (rsp->EncryptionKeyLength ==
522 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
523 memcpy(server->cryptkey, rsp->EncryptionKey,
524 CIFS_CRYPTO_KEY_SIZE);
525 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
526 return -EIO; /* need cryptkey unless plain text */
527 }
528
529 cifs_dbg(FYI, "LANMAN negotiated\n");
530 return 0;
531}
532#else
533static inline int
534decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
535 unsigned int secFlags)
536{
537 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
538 return -EOPNOTSUPP;
539}
540#endif
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400543CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 NEGOTIATE_REQ *pSMB;
546 NEGOTIATE_RSP *pSMBr;
547 int rc = 0;
548 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000549 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400550 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000552 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Jeff Layton3534b852013-05-24 07:41:01 -0400554 if (!server) {
555 WARN(1, "%s: server is NULL!\n", __func__);
556 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 }
Jeff Layton3534b852013-05-24 07:41:01 -0400558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
560 (void **) &pSMB, (void **) &pSMBr);
561 if (rc)
562 return rc;
Steve French750d1152006-06-27 06:28:30 +0000563
564 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000565 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000566 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000567 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400568 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000569
Joe Perchesf96637b2013-05-04 22:12:25 -0500570 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000571
Pavel Shilovsky88257362012-05-23 14:01:59 +0400572 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000573 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000574
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000575 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000576 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000577 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500578 cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
Steve Frencha0136892007-10-04 20:05:09 +0000579 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500580 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000581 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
582 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500583 cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000584 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
585 }
Steve French50c2f752007-07-13 00:33:32 +0000586
Steve French39798772006-05-31 22:40:51 +0000587 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000588 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000589 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
590 count += strlen(protocols[i].name) + 1;
591 /* null at end of source and target buffers anyway */
592 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000593 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 pSMB->ByteCount = cpu_to_le16(count);
595
596 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
597 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000598 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000599 goto neg_err_exit;
600
Jeff Layton9bf67e52010-04-24 07:57:46 -0400601 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500602 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000603 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400604 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000605 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000606 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000607 could not negotiate a common dialect */
608 rc = -EOPNOTSUPP;
609 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000610 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Layton2190eca2013-05-26 07:00:57 -0400611 rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
Jeff Layton9ddec562013-05-26 07:00:58 -0400612 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000613 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000614 /* unknown wct */
615 rc = -EOPNOTSUPP;
616 goto neg_err_exit;
617 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400618 /* else wct == 17, NTLM or better */
619
Steve French96daf2b2011-05-27 04:34:02 +0000620 server->sec_mode = pSMBr->SecurityMode;
621 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500622 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000623
Steve French96daf2b2011-05-27 04:34:02 +0000624 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000625#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000626 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000627#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500628 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000629
Steve French790fe572007-07-07 19:25:05 +0000630 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000631 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000632 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000633 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000634 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000635 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000636 else if (secFlags & CIFSSEC_MAY_KRB5)
637 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000638 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000639 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000640 else if (secFlags & CIFSSEC_MAY_LANMAN)
641 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000642 else {
643 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500644 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000645 goto neg_err_exit;
646 }
647 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000648
Steve French254e55e2006-06-04 05:53:15 +0000649 /* one byte, so no need to convert this or EncryptionKeyLen from
650 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300651 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
652 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400653 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000654 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400655 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000656 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500657 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000658 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000659 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
660 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400661
662 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE)
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500663 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000664 CIFS_CRYPTO_KEY_SIZE);
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400665 else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
Steve French07cc6cf2011-05-27 04:12:29 +0000666 server->capabilities & CAP_EXTENDED_SECURITY) &&
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400667 (pSMBr->EncryptionKeyLength == 0))
668 rc = decode_ext_sec_blob(server, pSMBr);
669 else if (server->sec_mode & SECMODE_PW_ENCRYPT)
Steve French07cc6cf2011-05-27 04:12:29 +0000670 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400671 else
Steve French254e55e2006-06-04 05:53:15 +0000672 server->capabilities &= ~CAP_EXTENDED_SECURITY;
673
674signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400675 if (!rc)
676 rc = cifs_enable_signing(server, secFlags);
Steve French50c2f752007-07-13 00:33:32 +0000677neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700678 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000679
Joe Perchesf96637b2013-05-04 22:12:25 -0500680 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return rc;
682}
683
684int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400685CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Joe Perchesf96637b2013-05-04 22:12:25 -0500690 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691
692 /* BB: do we need to check this? These should never be NULL. */
693 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
694 return -EIO;
695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500697 * No need to return error on this operation if tid invalidated and
698 * closed on server already e.g. due to tcp session crashing. Also,
699 * the tcon is no longer on the list, so no need to take lock before
700 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 */
Steve French268875b2009-06-25 00:29:21 +0000702 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000703 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Steve French50c2f752007-07-13 00:33:32 +0000705 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700706 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500707 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return rc;
Steve French133672e2007-11-13 22:41:37 +0000709
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400710 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500712 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Steve French50c2f752007-07-13 00:33:32 +0000714 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500715 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if (rc == -EAGAIN)
717 rc = 0;
718
719 return rc;
720}
721
Jeff Layton766fdbb2011-01-11 07:24:21 -0500722/*
723 * This is a no-op for now. We're not really interested in the reply, but
724 * rather in the fact that the server sent one and that server->lstrp
725 * gets updated.
726 *
727 * FIXME: maybe we should consider checking that the reply matches request?
728 */
729static void
730cifs_echo_callback(struct mid_q_entry *mid)
731{
732 struct TCP_Server_Info *server = mid->callback_data;
733
734 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400735 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500736}
737
738int
739CIFSSMBEcho(struct TCP_Server_Info *server)
740{
741 ECHO_REQ *smb;
742 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400743 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700744 struct smb_rqst rqst = { .rq_iov = &iov,
745 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
Joe Perchesf96637b2013-05-04 22:12:25 -0500747 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748
749 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
750 if (rc)
751 return rc;
752
753 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000754 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500755 smb->hdr.WordCount = 1;
756 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400757 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500758 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000759 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400760 iov.iov_base = smb;
761 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500762
Jeff Laytonfec344e2012-09-18 16:20:35 -0700763 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400764 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500765 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500766 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500767
768 cifs_small_buf_release(smb);
769
770 return rc;
771}
772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400774CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 LOGOFF_ANDX_REQ *pSMB;
777 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Joe Perchesf96637b2013-05-04 22:12:25 -0500779 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500780
781 /*
782 * BB: do we need to check validity of ses and server? They should
783 * always be valid since we have an active reference. If not, that
784 * should probably be a BUG()
785 */
786 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 return -EIO;
788
Steve Frenchd7b619c2010-02-25 05:36:46 +0000789 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000790 if (ses->need_reconnect)
791 goto session_already_dead; /* no need to send SMBlogoff if uid
792 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
794 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000795 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return rc;
797 }
798
Pavel Shilovsky88257362012-05-23 14:01:59 +0400799 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700800
Steve French96daf2b2011-05-27 04:34:02 +0000801 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
803 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
805 pSMB->hdr.Uid = ses->Suid;
806
807 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400808 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000809session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000810 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000813 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 error */
815 if (rc == -EAGAIN)
816 rc = 0;
817 return rc;
818}
819
820int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400821CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
822 const char *fileName, __u16 type,
823 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000824{
825 TRANSACTION2_SPI_REQ *pSMB = NULL;
826 TRANSACTION2_SPI_RSP *pSMBr = NULL;
827 struct unlink_psx_rq *pRqD;
828 int name_len;
829 int rc = 0;
830 int bytes_returned = 0;
831 __u16 params, param_offset, offset, byte_count;
832
Joe Perchesf96637b2013-05-04 22:12:25 -0500833 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000834PsxDelete:
835 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
836 (void **) &pSMBr);
837 if (rc)
838 return rc;
839
840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
841 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600842 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
843 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000844 name_len++; /* trailing null */
845 name_len *= 2;
846 } else { /* BB add path length overrun check */
847 name_len = strnlen(fileName, PATH_MAX);
848 name_len++; /* trailing null */
849 strncpy(pSMB->FileName, fileName, name_len);
850 }
851
852 params = 6 + name_len;
853 pSMB->MaxParameterCount = cpu_to_le16(2);
854 pSMB->MaxDataCount = 0; /* BB double check this with jra */
855 pSMB->MaxSetupCount = 0;
856 pSMB->Reserved = 0;
857 pSMB->Flags = 0;
858 pSMB->Timeout = 0;
859 pSMB->Reserved2 = 0;
860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
861 InformationLevel) - 4;
862 offset = param_offset + params;
863
864 /* Setup pointer to Request Data (inode type) */
865 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
866 pRqD->type = cpu_to_le16(type);
867 pSMB->ParameterOffset = cpu_to_le16(param_offset);
868 pSMB->DataOffset = cpu_to_le16(offset);
869 pSMB->SetupCount = 1;
870 pSMB->Reserved3 = 0;
871 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
872 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
873
874 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
875 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
876 pSMB->ParameterCount = cpu_to_le16(params);
877 pSMB->TotalParameterCount = pSMB->ParameterCount;
878 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
879 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000880 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000881 pSMB->ByteCount = cpu_to_le16(byte_count);
882 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
883 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000884 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500885 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000886 cifs_buf_release(pSMB);
887
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400888 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000889
890 if (rc == -EAGAIN)
891 goto PsxDelete;
892
893 return rc;
894}
895
896int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700897CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
898 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 DELETE_FILE_REQ *pSMB = NULL;
901 DELETE_FILE_RSP *pSMBr = NULL;
902 int rc = 0;
903 int bytes_returned;
904 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700905 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
907DelFileRetry:
908 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
909 (void **) &pSMBr);
910 if (rc)
911 return rc;
912
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700914 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
915 PATH_MAX, cifs_sb->local_nls,
916 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 name_len++; /* trailing null */
918 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700919 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700920 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700922 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
924 pSMB->SearchAttributes =
925 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
926 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000927 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 pSMB->ByteCount = cpu_to_le16(name_len + 1);
929 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400931 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000932 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500933 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 cifs_buf_release(pSMB);
936 if (rc == -EAGAIN)
937 goto DelFileRetry;
938
939 return rc;
940}
941
942int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400943CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
944 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
946 DELETE_DIRECTORY_REQ *pSMB = NULL;
947 DELETE_DIRECTORY_RSP *pSMBr = NULL;
948 int rc = 0;
949 int bytes_returned;
950 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Joe Perchesf96637b2013-05-04 22:12:25 -0500953 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954RmDirRetry:
955 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
959
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400961 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
962 PATH_MAX, cifs_sb->local_nls,
963 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 name_len++; /* trailing null */
965 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700966 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400967 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400969 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 }
971
972 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000973 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 pSMB->ByteCount = cpu_to_le16(name_len + 1);
975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400977 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000978 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500979 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 cifs_buf_release(pSMB);
982 if (rc == -EAGAIN)
983 goto RmDirRetry;
984 return rc;
985}
986
987int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300988CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
989 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 int rc = 0;
992 CREATE_DIRECTORY_REQ *pSMB = NULL;
993 CREATE_DIRECTORY_RSP *pSMBr = NULL;
994 int bytes_returned;
995 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300996 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Joe Perchesf96637b2013-05-04 22:12:25 -0500998 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999MkDirRetry:
1000 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1001 (void **) &pSMBr);
1002 if (rc)
1003 return rc;
1004
1005 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001006 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001007 PATH_MAX, cifs_sb->local_nls,
1008 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 name_len++; /* trailing null */
1010 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001011 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 name_len = strnlen(name, PATH_MAX);
1013 name_len++; /* trailing null */
1014 strncpy(pSMB->DirName, name, name_len);
1015 }
1016
1017 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001018 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1020 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1021 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001022 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001023 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001024 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 cifs_buf_release(pSMB);
1027 if (rc == -EAGAIN)
1028 goto MkDirRetry;
1029 return rc;
1030}
1031
Steve French2dd29d32007-04-23 22:07:35 +00001032int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001033CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1034 __u32 posix_flags, __u64 mode, __u16 *netfid,
1035 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1036 const char *name, const struct nls_table *nls_codepage,
1037 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001038{
1039 TRANSACTION2_SPI_REQ *pSMB = NULL;
1040 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1041 int name_len;
1042 int rc = 0;
1043 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001044 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001045 OPEN_PSX_REQ *pdata;
1046 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001047
Joe Perchesf96637b2013-05-04 22:12:25 -05001048 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001049PsxCreat:
1050 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1051 (void **) &pSMBr);
1052 if (rc)
1053 return rc;
1054
1055 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1056 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001057 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1058 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001059 name_len++; /* trailing null */
1060 name_len *= 2;
1061 } else { /* BB improve the check for buffer overruns BB */
1062 name_len = strnlen(name, PATH_MAX);
1063 name_len++; /* trailing null */
1064 strncpy(pSMB->FileName, name, name_len);
1065 }
1066
1067 params = 6 + name_len;
1068 count = sizeof(OPEN_PSX_REQ);
1069 pSMB->MaxParameterCount = cpu_to_le16(2);
1070 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1071 pSMB->MaxSetupCount = 0;
1072 pSMB->Reserved = 0;
1073 pSMB->Flags = 0;
1074 pSMB->Timeout = 0;
1075 pSMB->Reserved2 = 0;
1076 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001077 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001078 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001080 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001081 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001082 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001083 pdata->OpenFlags = cpu_to_le32(*pOplock);
1084 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1085 pSMB->DataOffset = cpu_to_le16(offset);
1086 pSMB->SetupCount = 1;
1087 pSMB->Reserved3 = 0;
1088 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1089 byte_count = 3 /* pad */ + params + count;
1090
1091 pSMB->DataCount = cpu_to_le16(count);
1092 pSMB->ParameterCount = cpu_to_le16(params);
1093 pSMB->TotalDataCount = pSMB->DataCount;
1094 pSMB->TotalParameterCount = pSMB->ParameterCount;
1095 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1096 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001097 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001098 pSMB->ByteCount = cpu_to_le16(byte_count);
1099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1101 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001102 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001103 goto psx_create_err;
1104 }
1105
Joe Perchesf96637b2013-05-04 22:12:25 -05001106 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001107 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1108
Jeff Layton820a8032011-05-04 08:05:26 -04001109 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001110 rc = -EIO; /* bad smb */
1111 goto psx_create_err;
1112 }
1113
1114 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001115 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001116 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001117
Steve French2dd29d32007-04-23 22:07:35 +00001118 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001119 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001120 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1121 /* Let caller know file was created so we can set the mode. */
1122 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001123 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001124 *pOplock |= CIFS_CREATE_ACTION;
1125 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001126 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1127 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001128 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001129 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001130 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001131 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001132 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001133 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001134 goto psx_create_err;
1135 }
Steve French50c2f752007-07-13 00:33:32 +00001136 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001137 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001138 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001139 }
Steve French2dd29d32007-04-23 22:07:35 +00001140
1141psx_create_err:
1142 cifs_buf_release(pSMB);
1143
Steve French65bc98b2009-07-10 15:27:25 +00001144 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001145 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001146 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001147 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001148
1149 if (rc == -EAGAIN)
1150 goto PsxCreat;
1151
Steve French50c2f752007-07-13 00:33:32 +00001152 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001153}
1154
Steve Frencha9d02ad2005-08-24 23:06:05 -07001155static __u16 convert_disposition(int disposition)
1156{
1157 __u16 ofun = 0;
1158
1159 switch (disposition) {
1160 case FILE_SUPERSEDE:
1161 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1162 break;
1163 case FILE_OPEN:
1164 ofun = SMBOPEN_OAPPEND;
1165 break;
1166 case FILE_CREATE:
1167 ofun = SMBOPEN_OCREATE;
1168 break;
1169 case FILE_OPEN_IF:
1170 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1171 break;
1172 case FILE_OVERWRITE:
1173 ofun = SMBOPEN_OTRUNC;
1174 break;
1175 case FILE_OVERWRITE_IF:
1176 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1177 break;
1178 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001179 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 ofun = SMBOPEN_OAPPEND; /* regular open */
1181 }
1182 return ofun;
1183}
1184
Jeff Layton35fc37d2008-05-14 10:22:03 -07001185static int
1186access_flags_to_smbopen_mode(const int access_flags)
1187{
1188 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1189
1190 if (masked_flags == GENERIC_READ)
1191 return SMBOPEN_READ;
1192 else if (masked_flags == GENERIC_WRITE)
1193 return SMBOPEN_WRITE;
1194
1195 /* just go for read/write */
1196 return SMBOPEN_READWRITE;
1197}
1198
Steve Frencha9d02ad2005-08-24 23:06:05 -07001199int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001200SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001201 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001202 const int access_flags, const int create_options, __u16 *netfid,
1203 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001204 const struct nls_table *nls_codepage, int remap)
1205{
1206 int rc = -EACCES;
1207 OPENX_REQ *pSMB = NULL;
1208 OPENX_RSP *pSMBr = NULL;
1209 int bytes_returned;
1210 int name_len;
1211 __u16 count;
1212
1213OldOpenRetry:
1214 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1215 (void **) &pSMBr);
1216 if (rc)
1217 return rc;
1218
1219 pSMB->AndXCommand = 0xFF; /* none */
1220
1221 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1222 count = 1; /* account for one byte pad to word boundary */
1223 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001224 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1225 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 name_len++; /* trailing null */
1227 name_len *= 2;
1228 } else { /* BB improve check for buffer overruns BB */
1229 count = 0; /* no pad */
1230 name_len = strnlen(fileName, PATH_MAX);
1231 name_len++; /* trailing null */
1232 strncpy(pSMB->fileName, fileName, name_len);
1233 }
1234 if (*pOplock & REQ_OPLOCK)
1235 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001236 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001238
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001240 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1242 /* set file as system file if special file such
1243 as fifo and server expecting SFU style and
1244 no Unix extensions */
1245
Steve French790fe572007-07-07 19:25:05 +00001246 if (create_options & CREATE_OPTION_SPECIAL)
1247 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001248 else /* BB FIXME BB */
1249 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250
Jeff Layton67750fb2008-05-09 22:28:02 +00001251 if (create_options & CREATE_OPTION_READONLY)
1252 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253
1254 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001255/* pSMB->CreateOptions = cpu_to_le32(create_options &
1256 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001258
1259 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001260 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001262 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263
1264 pSMB->ByteCount = cpu_to_le16(count);
1265 /* long_op set to 1 to allow for oplock break timeouts */
1266 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001267 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001268 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001270 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 } else {
1272 /* BB verify if wct == 15 */
1273
Steve French582d21e2008-05-13 04:54:12 +00001274/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275
1276 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1277 /* Let caller know file was created so we can set the mode. */
1278 /* Do we care about the CreateAction in any other cases? */
1279 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001280/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 *pOplock |= CIFS_CREATE_ACTION; */
1282 /* BB FIXME END */
1283
Steve French790fe572007-07-07 19:25:05 +00001284 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001285 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1286 pfile_info->LastAccessTime = 0; /* BB fixme */
1287 pfile_info->LastWriteTime = 0; /* BB fixme */
1288 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001289 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001290 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001291 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001292 pfile_info->AllocationSize =
1293 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1294 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001295 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001296 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297 }
1298 }
1299
1300 cifs_buf_release(pSMB);
1301 if (rc == -EAGAIN)
1302 goto OldOpenRetry;
1303 return rc;
1304}
1305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001307CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001309 const int access_flags, const int create_options, __u16 *netfid,
1310 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001311 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
1313 int rc = -EACCES;
1314 OPEN_REQ *pSMB = NULL;
1315 OPEN_RSP *pSMBr = NULL;
1316 int bytes_returned;
1317 int name_len;
1318 __u16 count;
1319
1320openRetry:
1321 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1322 (void **) &pSMBr);
1323 if (rc)
1324 return rc;
1325
1326 pSMB->AndXCommand = 0xFF; /* none */
1327
1328 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1329 count = 1; /* account for one byte pad to word boundary */
1330 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001331 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1332 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 name_len++; /* trailing null */
1334 name_len *= 2;
1335 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001336 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 count = 0; /* no pad */
1338 name_len = strnlen(fileName, PATH_MAX);
1339 name_len++; /* trailing null */
1340 pSMB->NameLength = cpu_to_le16(name_len);
1341 strncpy(pSMB->fileName, fileName, name_len);
1342 }
1343 if (*pOplock & REQ_OPLOCK)
1344 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001345 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1348 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001349 /* set file as system file if special file such
1350 as fifo and server expecting SFU style and
1351 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001352 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001353 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1354 else
1355 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 /* XP does not handle ATTR_POSIX_SEMANTICS */
1358 /* but it helps speed up case sensitive checks for other
1359 servers such as Samba */
1360 if (tcon->ses->capabilities & CAP_UNIX)
1361 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1362
Jeff Layton67750fb2008-05-09 22:28:02 +00001363 if (create_options & CREATE_OPTION_READONLY)
1364 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1365
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1367 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001368 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001369 /* BB Expirement with various impersonation levels and verify */
1370 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 pSMB->SecurityFlags =
1372 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1373
1374 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001375 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
1377 pSMB->ByteCount = cpu_to_le16(count);
1378 /* long_op set to 1 to allow for oplock break timeouts */
1379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001380 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001381 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001383 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 } else {
Steve French09d1db52005-04-28 22:41:08 -07001385 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1387 /* Let caller know file was created so we can set the mode. */
1388 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001389 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001390 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001391 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001392 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1393 36 /* CreationTime to Attributes */);
1394 /* the file_info buf is endian converted by caller */
1395 pfile_info->AllocationSize = pSMBr->AllocationSize;
1396 pfile_info->EndOfFile = pSMBr->EndOfFile;
1397 pfile_info->NumberOfLinks = cpu_to_le32(1);
1398 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001401
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 cifs_buf_release(pSMB);
1403 if (rc == -EAGAIN)
1404 goto openRetry;
1405 return rc;
1406}
1407
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001408/*
1409 * Discard any remaining data in the current SMB. To do this, we borrow the
1410 * current bigbuf.
1411 */
1412static int
1413cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1414{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001415 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001416 int remaining = rfclen + 4 - server->total_read;
1417 struct cifs_readdata *rdata = mid->callback_data;
1418
1419 while (remaining > 0) {
1420 int length;
1421
1422 length = cifs_read_from_socket(server, server->bigbuf,
1423 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001424 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425 if (length < 0)
1426 return length;
1427 server->total_read += length;
1428 remaining -= length;
1429 }
1430
1431 dequeue_mid(mid, rdata->result);
1432 return 0;
1433}
1434
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001435int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001436cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1437{
1438 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001439 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001441 char *buf = server->smallbuf;
1442 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443
Joe Perchesf96637b2013-05-04 22:12:25 -05001444 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1445 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446
1447 /*
1448 * read the rest of READ_RSP header (sans Data array), or whatever we
1449 * can if there's not enough data. At this point, we've read down to
1450 * the Mid.
1451 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001452 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001453 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001454
Jeff Layton58195752012-09-19 06:22:34 -07001455 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1456 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457
Jeff Layton58195752012-09-19 06:22:34 -07001458 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001459 if (length < 0)
1460 return length;
1461 server->total_read += length;
1462
1463 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001464 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001466 cifs_dbg(FYI, "%s: server returned error %d\n",
1467 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001468 return cifs_readv_discard(server, mid);
1469 }
1470
1471 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001472 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001473 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1474 __func__, server->total_read,
1475 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476 rdata->result = -EIO;
1477 return cifs_readv_discard(server, mid);
1478 }
1479
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001480 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 if (data_offset < server->total_read) {
1482 /*
1483 * win2k8 sometimes sends an offset of 0 when the read
1484 * is beyond the EOF. Treat it as if the data starts just after
1485 * the header.
1486 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001487 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1488 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 data_offset = server->total_read;
1490 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1491 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001492 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1493 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001494 rdata->result = -EIO;
1495 return cifs_readv_discard(server, mid);
1496 }
1497
Joe Perchesf96637b2013-05-04 22:12:25 -05001498 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1499 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001500
1501 len = data_offset - server->total_read;
1502 if (len > 0) {
1503 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001504 rdata->iov.iov_base = buf + server->total_read;
1505 rdata->iov.iov_len = len;
1506 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001507 if (length < 0)
1508 return length;
1509 server->total_read += length;
1510 }
1511
1512 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001513 rdata->iov.iov_base = buf;
1514 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001515 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1516 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001517
1518 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001519 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001520 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001521 /* data_len is corrupt -- discard frame */
1522 rdata->result = -EIO;
1523 return cifs_readv_discard(server, mid);
1524 }
1525
Jeff Layton8321fec2012-09-19 06:22:32 -07001526 length = rdata->read_into_pages(server, rdata, data_len);
1527 if (length < 0)
1528 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529
Jeff Layton8321fec2012-09-19 06:22:32 -07001530 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531 rdata->bytes = length;
1532
Joe Perchesf96637b2013-05-04 22:12:25 -05001533 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1534 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001535
1536 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001537 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001538 return cifs_readv_discard(server, mid);
1539
1540 dequeue_mid(mid, false);
1541 return length;
1542}
1543
1544static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545cifs_readv_callback(struct mid_q_entry *mid)
1546{
1547 struct cifs_readdata *rdata = mid->callback_data;
1548 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1549 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001550 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1551 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001552 .rq_pages = rdata->pages,
1553 .rq_npages = rdata->nr_pages,
1554 .rq_pagesz = rdata->pagesz,
1555 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556
Joe Perchesf96637b2013-05-04 22:12:25 -05001557 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1558 __func__, mid->mid, mid->mid_state, rdata->result,
1559 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001561 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001562 case MID_RESPONSE_RECEIVED:
1563 /* result already set, check signature */
1564 if (server->sec_mode &
1565 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff2012-08-03 09:42:45 -05001566 int rc = 0;
1567
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001568 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001569 mid->sequence_number);
Steve French985e4ff2012-08-03 09:42:45 -05001570 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001571 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1572 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573 }
1574 /* FIXME: should this be counted toward the initiating task? */
1575 task_io_account_read(rdata->bytes);
1576 cifs_stats_bytes_read(tcon, rdata->bytes);
1577 break;
1578 case MID_REQUEST_SUBMITTED:
1579 case MID_RETRY_NEEDED:
1580 rdata->result = -EAGAIN;
1581 break;
1582 default:
1583 rdata->result = -EIO;
1584 }
1585
Jeff Laytonda472fc2012-03-23 14:40:53 -04001586 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001588 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001589}
1590
1591/* cifs_async_readv - send an async write, and set up mid to handle result */
1592int
1593cifs_async_readv(struct cifs_readdata *rdata)
1594{
1595 int rc;
1596 READ_REQ *smb = NULL;
1597 int wct;
1598 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001599 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001600 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001601
Joe Perchesf96637b2013-05-04 22:12:25 -05001602 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1603 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001604
1605 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1606 wct = 12;
1607 else {
1608 wct = 10; /* old style read */
1609 if ((rdata->offset >> 32) > 0) {
1610 /* can not handle this big offset for old */
1611 return -EIO;
1612 }
1613 }
1614
1615 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1616 if (rc)
1617 return rc;
1618
1619 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1620 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1621
1622 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001623 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001624 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1625 if (wct == 12)
1626 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1627 smb->Remaining = 0;
1628 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1629 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1630 if (wct == 12)
1631 smb->ByteCount = 0;
1632 else {
1633 /* old style read */
1634 struct smb_com_readx_req *smbr =
1635 (struct smb_com_readx_req *)smb;
1636 smbr->ByteCount = 0;
1637 }
1638
1639 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001640 rdata->iov.iov_base = smb;
1641 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001642
Jeff Layton6993f742012-05-16 07:13:17 -04001643 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001644 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1645 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001646
1647 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001648 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001649 else
1650 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001651
1652 cifs_small_buf_release(smb);
1653 return rc;
1654}
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001657CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1658 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659{
1660 int rc = -EACCES;
1661 READ_REQ *pSMB = NULL;
1662 READ_RSP *pSMBr = NULL;
1663 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001664 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001665 int resp_buf_type = 0;
1666 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001667 __u32 pid = io_parms->pid;
1668 __u16 netfid = io_parms->netfid;
1669 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001670 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001671 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
Joe Perchesf96637b2013-05-04 22:12:25 -05001673 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001674 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001675 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001676 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001677 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001678 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001679 /* can not handle this big offset for old */
1680 return -EIO;
1681 }
1682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
1684 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001685 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (rc)
1687 return rc;
1688
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001689 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1690 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 /* tcon and ses pointer are checked in smb_init */
1693 if (tcon->ses->server == NULL)
1694 return -ECONNABORTED;
1695
Steve Frenchec637e32005-12-12 20:53:18 -08001696 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001698 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001699 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001700 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 pSMB->Remaining = 0;
1703 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1704 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001705 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001706 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1707 else {
1708 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001709 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001710 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001711 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001712 }
Steve Frenchec637e32005-12-12 20:53:18 -08001713
1714 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001715 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001716 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001717 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001718 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001719 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001721 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 } else {
1723 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1724 data_length = data_length << 16;
1725 data_length += le16_to_cpu(pSMBr->DataLength);
1726 *nbytes = data_length;
1727
1728 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001729 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001731 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001732 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 rc = -EIO;
1734 *nbytes = 0;
1735 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001736 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001737 le16_to_cpu(pSMBr->DataOffset);
1738/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001739 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001740 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001741 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001742 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001743 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
1745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
Steve French4b8f9302006-02-26 16:41:18 +00001747/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001748 if (*buf) {
1749 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001750 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001751 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001752 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001753 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001754 /* return buffer to caller to free */
1755 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001756 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001757 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001758 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001759 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001760 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001761
1762 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 since file handle passed in no longer valid */
1764 return rc;
1765}
1766
Steve Frenchec637e32005-12-12 20:53:18 -08001767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001769CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001770 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001771 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772{
1773 int rc = -EACCES;
1774 WRITE_REQ *pSMB = NULL;
1775 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001776 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 __u32 bytes_sent;
1778 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001779 __u32 pid = io_parms->pid;
1780 __u16 netfid = io_parms->netfid;
1781 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001782 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001783 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Steve Frencha24e2d72010-04-03 17:20:21 +00001785 *nbytes = 0;
1786
Joe Perchesf96637b2013-05-04 22:12:25 -05001787 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001788 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001789 return -ECONNABORTED;
1790
Steve French790fe572007-07-07 19:25:05 +00001791 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001792 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001793 else {
Steve French1c955182005-08-30 20:58:07 -07001794 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001795 if ((offset >> 32) > 0) {
1796 /* can not handle big offset for old srv */
1797 return -EIO;
1798 }
1799 }
Steve French1c955182005-08-30 20:58:07 -07001800
1801 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 (void **) &pSMBr);
1803 if (rc)
1804 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001805
1806 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1807 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* tcon and ses pointer are checked in smb_init */
1810 if (tcon->ses->server == NULL)
1811 return -ECONNABORTED;
1812
1813 pSMB->AndXCommand = 0xFF; /* none */
1814 pSMB->Fid = netfid;
1815 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001816 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001817 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 pSMB->Reserved = 0xFFFFFFFF;
1820 pSMB->WriteMode = 0;
1821 pSMB->Remaining = 0;
1822
Steve French50c2f752007-07-13 00:33:32 +00001823 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 can send more if LARGE_WRITE_X capability returned by the server and if
1825 our buffer is big enough or if we convert to iovecs on socket writes
1826 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001827 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1829 } else {
1830 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1831 & ~0xFF;
1832 }
1833
1834 if (bytes_sent > count)
1835 bytes_sent = count;
1836 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001837 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001838 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001839 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001840 else if (ubuf) {
1841 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 cifs_buf_release(pSMB);
1843 return -EFAULT;
1844 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001845 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 /* No buffer */
1847 cifs_buf_release(pSMB);
1848 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001849 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001850 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001851 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001852 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001853 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1856 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001857 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001858
Steve French790fe572007-07-07 19:25:05 +00001859 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001860 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001861 else { /* old style write has byte count 4 bytes earlier
1862 so 4 bytes pad */
1863 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001864 (struct smb_com_writex_req *)pSMB;
1865 pSMBW->ByteCount = cpu_to_le16(byte_count);
1866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1869 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001870 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001872 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 } else {
1874 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1875 *nbytes = (*nbytes) << 16;
1876 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301877
1878 /*
1879 * Mask off high 16 bits when bytes written as returned by the
1880 * server is greater than bytes requested by the client. Some
1881 * OS/2 servers are known to set incorrect CountHigh values.
1882 */
1883 if (*nbytes > count)
1884 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 }
1886
1887 cifs_buf_release(pSMB);
1888
Steve French50c2f752007-07-13 00:33:32 +00001889 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 since file handle passed in no longer valid */
1891
1892 return rc;
1893}
1894
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001895void
1896cifs_writedata_release(struct kref *refcount)
1897{
1898 struct cifs_writedata *wdata = container_of(refcount,
1899 struct cifs_writedata, refcount);
1900
1901 if (wdata->cfile)
1902 cifsFileInfo_put(wdata->cfile);
1903
1904 kfree(wdata);
1905}
1906
1907/*
1908 * Write failed with a retryable error. Resend the write request. It's also
1909 * possible that the page was redirtied so re-clean the page.
1910 */
1911static void
1912cifs_writev_requeue(struct cifs_writedata *wdata)
1913{
1914 int i, rc;
1915 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001916 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001917
1918 for (i = 0; i < wdata->nr_pages; i++) {
1919 lock_page(wdata->pages[i]);
1920 clear_page_dirty_for_io(wdata->pages[i]);
1921 }
1922
1923 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001924 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1925 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001926 } while (rc == -EAGAIN);
1927
1928 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001929 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001930 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001931 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001932 end_page_writeback(wdata->pages[i]);
1933 page_cache_release(wdata->pages[i]);
1934 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001935 }
1936
1937 mapping_set_error(inode->i_mapping, rc);
1938 kref_put(&wdata->refcount, cifs_writedata_release);
1939}
1940
Jeff Laytonc2e87642012-03-23 14:40:55 -04001941void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001942cifs_writev_complete(struct work_struct *work)
1943{
1944 struct cifs_writedata *wdata = container_of(work,
1945 struct cifs_writedata, work);
1946 struct inode *inode = wdata->cfile->dentry->d_inode;
1947 int i = 0;
1948
1949 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001950 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001951 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001952 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001953 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1954 wdata->bytes);
1955 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1956 return cifs_writev_requeue(wdata);
1957
1958 for (i = 0; i < wdata->nr_pages; i++) {
1959 struct page *page = wdata->pages[i];
1960 if (wdata->result == -EAGAIN)
1961 __set_page_dirty_nobuffers(page);
1962 else if (wdata->result < 0)
1963 SetPageError(page);
1964 end_page_writeback(page);
1965 page_cache_release(page);
1966 }
1967 if (wdata->result != -EAGAIN)
1968 mapping_set_error(inode->i_mapping, wdata->result);
1969 kref_put(&wdata->refcount, cifs_writedata_release);
1970}
1971
1972struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001973cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001974{
1975 struct cifs_writedata *wdata;
1976
1977 /* this would overflow */
1978 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001979 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001980 return NULL;
1981 }
1982
1983 /* writedata + number of page pointers */
1984 wdata = kzalloc(sizeof(*wdata) +
1985 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1986 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001987 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001988 INIT_LIST_HEAD(&wdata->list);
1989 init_completion(&wdata->done);
1990 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001991 }
1992 return wdata;
1993}
1994
1995/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001996 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001997 * workqueue completion task.
1998 */
1999static void
2000cifs_writev_callback(struct mid_q_entry *mid)
2001{
2002 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002003 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002004 unsigned int written;
2005 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2006
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002007 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002008 case MID_RESPONSE_RECEIVED:
2009 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2010 if (wdata->result != 0)
2011 break;
2012
2013 written = le16_to_cpu(smb->CountHigh);
2014 written <<= 16;
2015 written += le16_to_cpu(smb->Count);
2016 /*
2017 * Mask off high 16 bits when bytes written as returned
2018 * by the server is greater than bytes requested by the
2019 * client. OS/2 servers are known to set incorrect
2020 * CountHigh values.
2021 */
2022 if (written > wdata->bytes)
2023 written &= 0xFFFF;
2024
2025 if (written < wdata->bytes)
2026 wdata->result = -ENOSPC;
2027 else
2028 wdata->bytes = written;
2029 break;
2030 case MID_REQUEST_SUBMITTED:
2031 case MID_RETRY_NEEDED:
2032 wdata->result = -EAGAIN;
2033 break;
2034 default:
2035 wdata->result = -EIO;
2036 break;
2037 }
2038
Jeff Laytonda472fc2012-03-23 14:40:53 -04002039 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002041 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002042}
2043
2044/* cifs_async_writev - send an async write, and set up mid to handle result */
2045int
2046cifs_async_writev(struct cifs_writedata *wdata)
2047{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002048 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002049 WRITE_REQ *smb = NULL;
2050 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002051 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002052 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002053 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002054
2055 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2056 wct = 14;
2057 } else {
2058 wct = 12;
2059 if (wdata->offset >> 32 > 0) {
2060 /* can not handle big offset for old srv */
2061 return -EIO;
2062 }
2063 }
2064
2065 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2066 if (rc)
2067 goto async_writev_out;
2068
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002069 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2070 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002071
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002072 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002073 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002074 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2075 if (wct == 14)
2076 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2077 smb->Reserved = 0xFFFFFFFF;
2078 smb->WriteMode = 0;
2079 smb->Remaining = 0;
2080
2081 smb->DataOffset =
2082 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2083
2084 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002085 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2086 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002087
Jeff Laytoneddb0792012-09-18 16:20:35 -07002088 rqst.rq_iov = &iov;
2089 rqst.rq_nvec = 1;
2090 rqst.rq_pages = wdata->pages;
2091 rqst.rq_npages = wdata->nr_pages;
2092 rqst.rq_pagesz = wdata->pagesz;
2093 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094
Joe Perchesf96637b2013-05-04 22:12:25 -05002095 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2096 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002097
2098 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2099 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2100
2101 if (wct == 14) {
2102 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2103 put_bcc(wdata->bytes + 1, &smb->hdr);
2104 } else {
2105 /* wct == 12 */
2106 struct smb_com_writex_req *smbw =
2107 (struct smb_com_writex_req *)smb;
2108 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2109 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002110 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111 }
2112
2113 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002114 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2115 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002116
2117 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002118 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002119 else
2120 kref_put(&wdata->refcount, cifs_writedata_release);
2121
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122async_writev_out:
2123 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002124 return rc;
2125}
2126
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002127int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002128CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad722012-09-18 16:20:30 -07002129 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130{
2131 int rc = -EACCES;
2132 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002133 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002134 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002135 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002136 __u32 pid = io_parms->pid;
2137 __u16 netfid = io_parms->netfid;
2138 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002139 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002140 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002142 *nbytes = 0;
2143
Joe Perchesf96637b2013-05-04 22:12:25 -05002144 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002145
Steve French4c3130e2008-12-09 00:28:16 +00002146 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002147 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002148 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002149 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002150 if ((offset >> 32) > 0) {
2151 /* can not handle big offset for old srv */
2152 return -EIO;
2153 }
2154 }
Steve French8cc64c62005-10-03 13:49:43 -07002155 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 if (rc)
2157 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002158
2159 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2160 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2161
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 /* tcon and ses pointer are checked in smb_init */
2163 if (tcon->ses->server == NULL)
2164 return -ECONNABORTED;
2165
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002166 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 pSMB->Fid = netfid;
2168 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002169 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002170 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 pSMB->Reserved = 0xFFFFFFFF;
2172 pSMB->WriteMode = 0;
2173 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002174
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002176 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
Steve French3e844692005-10-03 13:37:24 -07002178 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2179 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002180 /* header + 1 byte pad */
2181 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002182 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002183 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002184 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002185 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002186 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002187 pSMB->ByteCount = cpu_to_le16(count + 1);
2188 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002189 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002190 (struct smb_com_writex_req *)pSMB;
2191 pSMBW->ByteCount = cpu_to_le16(count + 5);
2192 }
Steve French3e844692005-10-03 13:37:24 -07002193 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002194 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002195 iov[0].iov_len = smb_hdr_len + 4;
2196 else /* wct == 12 pad bigger by four bytes */
2197 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002198
Steve French3e844692005-10-03 13:37:24 -07002199
Pavel Shilovskyba9ad722012-09-18 16:20:30 -07002200 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002201 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002203 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002204 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002205 /* presumably this can not happen, but best to be safe */
2206 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002207 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002208 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002209 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2210 *nbytes = (*nbytes) << 16;
2211 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302212
2213 /*
2214 * Mask off high 16 bits when bytes written as returned by the
2215 * server is greater than bytes requested by the client. OS/2
2216 * servers are known to set incorrect CountHigh values.
2217 */
2218 if (*nbytes > count)
2219 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
Steve French4b8f9302006-02-26 16:41:18 +00002222/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002223 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002224 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002225 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002226 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
Steve French50c2f752007-07-13 00:33:32 +00002228 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 since file handle passed in no longer valid */
2230
2231 return rc;
2232}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002233
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002234int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2235 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002236 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2237{
2238 int rc = 0;
2239 LOCK_REQ *pSMB = NULL;
2240 struct kvec iov[2];
2241 int resp_buf_type;
2242 __u16 count;
2243
Joe Perchesf96637b2013-05-04 22:12:25 -05002244 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2245 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002246
2247 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2248 if (rc)
2249 return rc;
2250
2251 pSMB->Timeout = 0;
2252 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2253 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2254 pSMB->LockType = lock_type;
2255 pSMB->AndXCommand = 0xFF; /* none */
2256 pSMB->Fid = netfid; /* netfid stays le */
2257
2258 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2259 inc_rfc1001_len(pSMB, count);
2260 pSMB->ByteCount = cpu_to_le16(count);
2261
2262 iov[0].iov_base = (char *)pSMB;
2263 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2264 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2265 iov[1].iov_base = (char *)buf;
2266 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2267
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002268 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002269 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2270 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002271 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002272
2273 return rc;
2274}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002275
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002277CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002278 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002280 const __u32 numLock, const __u8 lockType,
2281 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282{
2283 int rc = 0;
2284 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002285/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002287 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 __u16 count;
2289
Joe Perchesf96637b2013-05-04 22:12:25 -05002290 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2291 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002292 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2293
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 if (rc)
2295 return rc;
2296
Steve French790fe572007-07-07 19:25:05 +00002297 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002298 /* no response expected */
2299 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002301 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002302 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2304 } else {
2305 pSMB->Timeout = 0;
2306 }
2307
2308 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2309 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2310 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002311 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 pSMB->AndXCommand = 0xFF; /* none */
2313 pSMB->Fid = smb_file_id; /* netfid stays le */
2314
Steve French790fe572007-07-07 19:25:05 +00002315 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002316 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 /* BB where to store pid high? */
2318 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2319 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2320 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2321 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2322 count = sizeof(LOCKING_ANDX_RANGE);
2323 } else {
2324 /* oplock break */
2325 count = 0;
2326 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002327 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 pSMB->ByteCount = cpu_to_le16(count);
2329
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002330 if (waitFlag) {
2331 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002332 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002333 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002334 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002335 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002336 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002337 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002338 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002339 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002340 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
Steve French50c2f752007-07-13 00:33:32 +00002342 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 since file handle passed in no longer valid */
2344 return rc;
2345}
2346
2347int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002348CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002349 const __u16 smb_file_id, const __u32 netpid,
2350 const loff_t start_offset, const __u64 len,
2351 struct file_lock *pLockData, const __u16 lock_type,
2352 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002353{
2354 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2355 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002356 struct cifs_posix_lock *parm_data;
2357 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002358 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002359 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002360 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002361 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002362 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002363
Joe Perchesf96637b2013-05-04 22:12:25 -05002364 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002365
Steve French08547b02006-02-28 22:39:25 +00002366 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2367
2368 if (rc)
2369 return rc;
2370
2371 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2372
Steve French50c2f752007-07-13 00:33:32 +00002373 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002374 pSMB->MaxSetupCount = 0;
2375 pSMB->Reserved = 0;
2376 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002377 pSMB->Reserved2 = 0;
2378 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2379 offset = param_offset + params;
2380
Steve French08547b02006-02-28 22:39:25 +00002381 count = sizeof(struct cifs_posix_lock);
2382 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002383 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002384 pSMB->SetupCount = 1;
2385 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002386 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002387 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2388 else
2389 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2390 byte_count = 3 /* pad */ + params + count;
2391 pSMB->DataCount = cpu_to_le16(count);
2392 pSMB->ParameterCount = cpu_to_le16(params);
2393 pSMB->TotalDataCount = pSMB->DataCount;
2394 pSMB->TotalParameterCount = pSMB->ParameterCount;
2395 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002396 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002397 (((char *) &pSMB->hdr.Protocol) + offset);
2398
2399 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002400 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002401 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002402 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002403 pSMB->Timeout = cpu_to_le32(-1);
2404 } else
2405 pSMB->Timeout = 0;
2406
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002407 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002408 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002409 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002410
2411 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002412 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002413 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2414 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002415 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002416 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002417 if (waitFlag) {
2418 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2419 (struct smb_hdr *) pSMBr, &bytes_returned);
2420 } else {
Steve French133672e2007-11-13 22:41:37 +00002421 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002422 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002423 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2424 &resp_buf_type, timeout);
2425 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2426 not try to free it twice below on exit */
2427 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002428 }
2429
Steve French08547b02006-02-28 22:39:25 +00002430 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002431 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002432 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002433 /* lock structure can be returned on get */
2434 __u16 data_offset;
2435 __u16 data_count;
2436 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002437
Jeff Layton820a8032011-05-04 08:05:26 -04002438 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002439 rc = -EIO; /* bad smb */
2440 goto plk_err_exit;
2441 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002442 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2443 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002444 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002445 rc = -EIO;
2446 goto plk_err_exit;
2447 }
2448 parm_data = (struct cifs_posix_lock *)
2449 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002450 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002451 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002452 else {
2453 if (parm_data->lock_type ==
2454 __constant_cpu_to_le16(CIFS_RDLCK))
2455 pLockData->fl_type = F_RDLCK;
2456 else if (parm_data->lock_type ==
2457 __constant_cpu_to_le16(CIFS_WRLCK))
2458 pLockData->fl_type = F_WRLCK;
2459
Steve French5443d132011-03-13 05:08:25 +00002460 pLockData->fl_start = le64_to_cpu(parm_data->start);
2461 pLockData->fl_end = pLockData->fl_start +
2462 le64_to_cpu(parm_data->length) - 1;
2463 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002464 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002465 }
Steve French50c2f752007-07-13 00:33:32 +00002466
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002467plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002468 if (pSMB)
2469 cifs_small_buf_release(pSMB);
2470
Steve French133672e2007-11-13 22:41:37 +00002471 if (resp_buf_type == CIFS_SMALL_BUFFER)
2472 cifs_small_buf_release(iov[0].iov_base);
2473 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2474 cifs_buf_release(iov[0].iov_base);
2475
Steve French08547b02006-02-28 22:39:25 +00002476 /* Note: On -EAGAIN error only caller can retry on handle based calls
2477 since file handle passed in no longer valid */
2478
2479 return rc;
2480}
2481
2482
2483int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002484CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485{
2486 int rc = 0;
2487 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002488 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490/* do not retry on dead session on close */
2491 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002492 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 return 0;
2494 if (rc)
2495 return rc;
2496
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002498 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002500 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002501 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002503 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002505 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
2507 }
2508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002510 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 rc = 0;
2512
2513 return rc;
2514}
2515
2516int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002517CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002518{
2519 int rc = 0;
2520 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002521 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002522
2523 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2524 if (rc)
2525 return rc;
2526
2527 pSMB->FileID = (__u16) smb_file_id;
2528 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002529 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002530 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002531 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002532 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002533
2534 return rc;
2535}
2536
2537int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002538CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002539 const char *from_name, const char *to_name,
2540 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541{
2542 int rc = 0;
2543 RENAME_REQ *pSMB = NULL;
2544 RENAME_RSP *pSMBr = NULL;
2545 int bytes_returned;
2546 int name_len, name_len2;
2547 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002548 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549
Joe Perchesf96637b2013-05-04 22:12:25 -05002550 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551renameRetry:
2552 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2553 (void **) &pSMBr);
2554 if (rc)
2555 return rc;
2556
2557 pSMB->BufferFormat = 0x04;
2558 pSMB->SearchAttributes =
2559 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2560 ATTR_DIRECTORY);
2561
2562 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002563 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2564 from_name, PATH_MAX,
2565 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 name_len++; /* trailing null */
2567 name_len *= 2;
2568 pSMB->OldFileName[name_len] = 0x04; /* pad */
2569 /* protocol requires ASCII signature byte on Unicode string */
2570 pSMB->OldFileName[name_len + 1] = 0x00;
2571 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002572 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002573 to_name, PATH_MAX, cifs_sb->local_nls,
2574 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2576 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002577 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002578 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002580 strncpy(pSMB->OldFileName, from_name, name_len);
2581 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 name_len2++; /* trailing null */
2583 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002584 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 name_len2++; /* trailing null */
2586 name_len2++; /* signature byte */
2587 }
2588
2589 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002590 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 pSMB->ByteCount = cpu_to_le16(count);
2592
2593 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2594 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002595 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002596 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002597 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 cifs_buf_release(pSMB);
2600
2601 if (rc == -EAGAIN)
2602 goto renameRetry;
2603
2604 return rc;
2605}
2606
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002607int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002608 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002609 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610{
2611 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2612 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002613 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 char *data_offset;
2615 char dummy_string[30];
2616 int rc = 0;
2617 int bytes_returned = 0;
2618 int len_of_str;
2619 __u16 params, param_offset, offset, count, byte_count;
2620
Joe Perchesf96637b2013-05-04 22:12:25 -05002621 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2623 (void **) &pSMBr);
2624 if (rc)
2625 return rc;
2626
2627 params = 6;
2628 pSMB->MaxSetupCount = 0;
2629 pSMB->Reserved = 0;
2630 pSMB->Flags = 0;
2631 pSMB->Timeout = 0;
2632 pSMB->Reserved2 = 0;
2633 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2634 offset = param_offset + params;
2635
2636 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2637 rename_info = (struct set_file_rename *) data_offset;
2638 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002639 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 pSMB->SetupCount = 1;
2641 pSMB->Reserved3 = 0;
2642 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2643 byte_count = 3 /* pad */ + params;
2644 pSMB->ParameterCount = cpu_to_le16(params);
2645 pSMB->TotalParameterCount = pSMB->ParameterCount;
2646 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2647 pSMB->DataOffset = cpu_to_le16(offset);
2648 /* construct random name ".cifs_tmp<inodenum><mid>" */
2649 rename_info->overwrite = cpu_to_le32(1);
2650 rename_info->root_fid = 0;
2651 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002652 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002653 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002654 len_of_str =
2655 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002656 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002658 len_of_str =
2659 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002660 target_name, PATH_MAX, nls_codepage,
2661 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 }
2663 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002664 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 byte_count += count;
2666 pSMB->DataCount = cpu_to_le16(count);
2667 pSMB->TotalDataCount = pSMB->DataCount;
2668 pSMB->Fid = netfid;
2669 pSMB->InformationLevel =
2670 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2671 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002672 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 pSMB->ByteCount = cpu_to_le16(byte_count);
2674 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002675 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002676 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002677 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002678 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2679 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 cifs_buf_release(pSMB);
2682
2683 /* Note: On -EAGAIN error only caller can retry on handle based calls
2684 since file handle passed in no longer valid */
2685
2686 return rc;
2687}
2688
2689int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002690CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2691 const char *fromName, const __u16 target_tid, const char *toName,
2692 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
2694 int rc = 0;
2695 COPY_REQ *pSMB = NULL;
2696 COPY_RSP *pSMBr = NULL;
2697 int bytes_returned;
2698 int name_len, name_len2;
2699 __u16 count;
2700
Joe Perchesf96637b2013-05-04 22:12:25 -05002701 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702copyRetry:
2703 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2704 (void **) &pSMBr);
2705 if (rc)
2706 return rc;
2707
2708 pSMB->BufferFormat = 0x04;
2709 pSMB->Tid2 = target_tid;
2710
2711 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2712
2713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002714 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2715 fromName, PATH_MAX, nls_codepage,
2716 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 name_len++; /* trailing null */
2718 name_len *= 2;
2719 pSMB->OldFileName[name_len] = 0x04; /* pad */
2720 /* protocol requires ASCII signature byte on Unicode string */
2721 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002722 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002723 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2724 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2726 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002727 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 name_len = strnlen(fromName, PATH_MAX);
2729 name_len++; /* trailing null */
2730 strncpy(pSMB->OldFileName, fromName, name_len);
2731 name_len2 = strnlen(toName, PATH_MAX);
2732 name_len2++; /* trailing null */
2733 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2734 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2735 name_len2++; /* trailing null */
2736 name_len2++; /* signature byte */
2737 }
2738
2739 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002740 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 pSMB->ByteCount = cpu_to_le16(count);
2742
2743 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2744 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2745 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002746 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2747 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 }
Steve French0d817bc2008-05-22 02:02:03 +00002749 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
2751 if (rc == -EAGAIN)
2752 goto copyRetry;
2753
2754 return rc;
2755}
2756
2757int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002758CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 const char *fromName, const char *toName,
2760 const struct nls_table *nls_codepage)
2761{
2762 TRANSACTION2_SPI_REQ *pSMB = NULL;
2763 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2764 char *data_offset;
2765 int name_len;
2766 int name_len_target;
2767 int rc = 0;
2768 int bytes_returned = 0;
2769 __u16 params, param_offset, offset, byte_count;
2770
Joe Perchesf96637b2013-05-04 22:12:25 -05002771 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772createSymLinkRetry:
2773 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2774 (void **) &pSMBr);
2775 if (rc)
2776 return rc;
2777
2778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2779 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002780 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2781 /* find define for this maxpathcomponent */
2782 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 name_len++; /* trailing null */
2784 name_len *= 2;
2785
Steve French50c2f752007-07-13 00:33:32 +00002786 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 name_len = strnlen(fromName, PATH_MAX);
2788 name_len++; /* trailing null */
2789 strncpy(pSMB->FileName, fromName, name_len);
2790 }
2791 params = 6 + name_len;
2792 pSMB->MaxSetupCount = 0;
2793 pSMB->Reserved = 0;
2794 pSMB->Flags = 0;
2795 pSMB->Timeout = 0;
2796 pSMB->Reserved2 = 0;
2797 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002798 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 offset = param_offset + params;
2800
2801 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2802 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2803 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002804 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2805 /* find define for this maxpathcomponent */
2806 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 name_len_target++; /* trailing null */
2808 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002809 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 name_len_target = strnlen(toName, PATH_MAX);
2811 name_len_target++; /* trailing null */
2812 strncpy(data_offset, toName, name_len_target);
2813 }
2814
2815 pSMB->MaxParameterCount = cpu_to_le16(2);
2816 /* BB find exact max on data count below from sess */
2817 pSMB->MaxDataCount = cpu_to_le16(1000);
2818 pSMB->SetupCount = 1;
2819 pSMB->Reserved3 = 0;
2820 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2821 byte_count = 3 /* pad */ + params + name_len_target;
2822 pSMB->DataCount = cpu_to_le16(name_len_target);
2823 pSMB->ParameterCount = cpu_to_le16(params);
2824 pSMB->TotalDataCount = pSMB->DataCount;
2825 pSMB->TotalParameterCount = pSMB->ParameterCount;
2826 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2827 pSMB->DataOffset = cpu_to_le16(offset);
2828 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2829 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002830 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 pSMB->ByteCount = cpu_to_le16(byte_count);
2832 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2833 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002834 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002835 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002836 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2837 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
Steve French0d817bc2008-05-22 02:02:03 +00002839 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
2841 if (rc == -EAGAIN)
2842 goto createSymLinkRetry;
2843
2844 return rc;
2845}
2846
2847int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002848CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002850 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851{
2852 TRANSACTION2_SPI_REQ *pSMB = NULL;
2853 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2854 char *data_offset;
2855 int name_len;
2856 int name_len_target;
2857 int rc = 0;
2858 int bytes_returned = 0;
2859 __u16 params, param_offset, offset, byte_count;
2860
Joe Perchesf96637b2013-05-04 22:12:25 -05002861 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862createHardLinkRetry:
2863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864 (void **) &pSMBr);
2865 if (rc)
2866 return rc;
2867
2868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002869 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2870 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 name_len++; /* trailing null */
2872 name_len *= 2;
2873
Steve French50c2f752007-07-13 00:33:32 +00002874 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len = strnlen(toName, PATH_MAX);
2876 name_len++; /* trailing null */
2877 strncpy(pSMB->FileName, toName, name_len);
2878 }
2879 params = 6 + name_len;
2880 pSMB->MaxSetupCount = 0;
2881 pSMB->Reserved = 0;
2882 pSMB->Flags = 0;
2883 pSMB->Timeout = 0;
2884 pSMB->Reserved2 = 0;
2885 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002886 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 offset = param_offset + params;
2888
2889 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2891 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002892 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2893 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 name_len_target++; /* trailing null */
2895 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002896 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 name_len_target = strnlen(fromName, PATH_MAX);
2898 name_len_target++; /* trailing null */
2899 strncpy(data_offset, fromName, name_len_target);
2900 }
2901
2902 pSMB->MaxParameterCount = cpu_to_le16(2);
2903 /* BB find exact max on data count below from sess*/
2904 pSMB->MaxDataCount = cpu_to_le16(1000);
2905 pSMB->SetupCount = 1;
2906 pSMB->Reserved3 = 0;
2907 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2908 byte_count = 3 /* pad */ + params + name_len_target;
2909 pSMB->ParameterCount = cpu_to_le16(params);
2910 pSMB->TotalParameterCount = pSMB->ParameterCount;
2911 pSMB->DataCount = cpu_to_le16(name_len_target);
2912 pSMB->TotalDataCount = pSMB->DataCount;
2913 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2914 pSMB->DataOffset = cpu_to_le16(offset);
2915 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2916 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002917 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 pSMB->ByteCount = cpu_to_le16(byte_count);
2919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002921 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002922 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002923 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2924 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
2926 cifs_buf_release(pSMB);
2927 if (rc == -EAGAIN)
2928 goto createHardLinkRetry;
2929
2930 return rc;
2931}
2932
2933int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002934CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002935 const char *from_name, const char *to_name,
2936 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937{
2938 int rc = 0;
2939 NT_RENAME_REQ *pSMB = NULL;
2940 RENAME_RSP *pSMBr = NULL;
2941 int bytes_returned;
2942 int name_len, name_len2;
2943 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002944 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
Joe Perchesf96637b2013-05-04 22:12:25 -05002946 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947winCreateHardLinkRetry:
2948
2949 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2950 (void **) &pSMBr);
2951 if (rc)
2952 return rc;
2953
2954 pSMB->SearchAttributes =
2955 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2956 ATTR_DIRECTORY);
2957 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2958 pSMB->ClusterCount = 0;
2959
2960 pSMB->BufferFormat = 0x04;
2961
2962 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2963 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002964 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2965 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 name_len++; /* trailing null */
2967 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002968
2969 /* protocol specifies ASCII buffer format (0x04) for unicode */
2970 pSMB->OldFileName[name_len] = 0x04;
2971 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002973 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002974 to_name, PATH_MAX, cifs_sb->local_nls,
2975 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2977 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002978 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002979 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002981 strncpy(pSMB->OldFileName, from_name, name_len);
2982 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 name_len2++; /* trailing null */
2984 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002985 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 name_len2++; /* trailing null */
2987 name_len2++; /* signature byte */
2988 }
2989
2990 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002991 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 pSMB->ByteCount = cpu_to_le16(count);
2993
2994 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002996 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002997 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002998 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002999
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 cifs_buf_release(pSMB);
3001 if (rc == -EAGAIN)
3002 goto winCreateHardLinkRetry;
3003
3004 return rc;
3005}
3006
3007int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003008CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003009 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 const struct nls_table *nls_codepage)
3011{
3012/* SMB_QUERY_FILE_UNIX_LINK */
3013 TRANSACTION2_QPI_REQ *pSMB = NULL;
3014 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3015 int rc = 0;
3016 int bytes_returned;
3017 int name_len;
3018 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003019 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
Joe Perchesf96637b2013-05-04 22:12:25 -05003021 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022
3023querySymLinkRetry:
3024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3025 (void **) &pSMBr);
3026 if (rc)
3027 return rc;
3028
3029 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3030 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003031 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3032 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 name_len++; /* trailing null */
3034 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003035 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 name_len = strnlen(searchName, PATH_MAX);
3037 name_len++; /* trailing null */
3038 strncpy(pSMB->FileName, searchName, name_len);
3039 }
3040
3041 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3042 pSMB->TotalDataCount = 0;
3043 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003044 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 pSMB->MaxSetupCount = 0;
3046 pSMB->Reserved = 0;
3047 pSMB->Flags = 0;
3048 pSMB->Timeout = 0;
3049 pSMB->Reserved2 = 0;
3050 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003051 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 pSMB->DataCount = 0;
3053 pSMB->DataOffset = 0;
3054 pSMB->SetupCount = 1;
3055 pSMB->Reserved3 = 0;
3056 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3057 byte_count = params + 1 /* pad */ ;
3058 pSMB->TotalParameterCount = cpu_to_le16(params);
3059 pSMB->ParameterCount = pSMB->TotalParameterCount;
3060 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3061 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003062 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 pSMB->ByteCount = cpu_to_le16(byte_count);
3064
3065 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3067 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003068 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 } else {
3070 /* decode response */
3071
3072 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003074 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003075 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003077 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003078 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
Jeff Layton460b9692009-04-30 07:17:56 -04003080 data_start = ((char *) &pSMBr->hdr.Protocol) +
3081 le16_to_cpu(pSMBr->t2.DataOffset);
3082
Steve French0e0d2cf2009-05-01 05:27:32 +00003083 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3084 is_unicode = true;
3085 else
3086 is_unicode = false;
3087
Steve French737b7582005-04-28 22:41:06 -07003088 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003089 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3090 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003091 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003092 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 }
3094 }
3095 cifs_buf_release(pSMB);
3096 if (rc == -EAGAIN)
3097 goto querySymLinkRetry;
3098 return rc;
3099}
3100
Steve Frenchc52a9552011-02-24 06:16:22 +00003101#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3102/*
3103 * Recent Windows versions now create symlinks more frequently
3104 * and they use the "reparse point" mechanism below. We can of course
3105 * do symlinks nicely to Samba and other servers which support the
3106 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3107 * "MF" symlinks optionally, but for recent Windows we really need to
3108 * reenable the code below and fix the cifs_symlink callers to handle this.
3109 * In the interim this code has been moved to its own config option so
3110 * it is not compiled in by default until callers fixed up and more tested.
3111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003113CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003115 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 const struct nls_table *nls_codepage)
3117{
3118 int rc = 0;
3119 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003120 struct smb_com_transaction_ioctl_req *pSMB;
3121 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
Joe Perchesf96637b2013-05-04 22:12:25 -05003123 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3124 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3126 (void **) &pSMBr);
3127 if (rc)
3128 return rc;
3129
3130 pSMB->TotalParameterCount = 0 ;
3131 pSMB->TotalDataCount = 0;
3132 pSMB->MaxParameterCount = cpu_to_le32(2);
3133 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003134 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 pSMB->MaxSetupCount = 4;
3136 pSMB->Reserved = 0;
3137 pSMB->ParameterOffset = 0;
3138 pSMB->DataCount = 0;
3139 pSMB->DataOffset = 0;
3140 pSMB->SetupCount = 4;
3141 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3142 pSMB->ParameterCount = pSMB->TotalParameterCount;
3143 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3144 pSMB->IsFsctl = 1; /* FSCTL */
3145 pSMB->IsRootFlag = 0;
3146 pSMB->Fid = fid; /* file handle always le */
3147 pSMB->ByteCount = 0;
3148
3149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3151 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003152 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 } else { /* decode response */
3154 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3155 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003156 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3157 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003159 goto qreparse_out;
3160 }
3161 if (data_count && (data_count < 2048)) {
3162 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003163 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
Steve Frenchafe48c32009-05-02 05:25:46 +00003165 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003166 (struct reparse_data *)
3167 ((char *)&pSMBr->hdr.Protocol
3168 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003169 if ((char *)reparse_buf >= end_of_smb) {
3170 rc = -EIO;
3171 goto qreparse_out;
3172 }
3173 if ((reparse_buf->LinkNamesBuf +
3174 reparse_buf->TargetNameOffset +
3175 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003176 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003177 rc = -EIO;
3178 goto qreparse_out;
3179 }
Steve French50c2f752007-07-13 00:33:32 +00003180
Steve Frenchafe48c32009-05-02 05:25:46 +00003181 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3182 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003183 (reparse_buf->LinkNamesBuf +
3184 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003185 buflen,
3186 reparse_buf->TargetNameLen,
3187 nls_codepage, 0);
3188 } else { /* ASCII names */
3189 strncpy(symlinkinfo,
3190 reparse_buf->LinkNamesBuf +
3191 reparse_buf->TargetNameOffset,
3192 min_t(const int, buflen,
3193 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003195 } else {
3196 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003197 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003199 symlinkinfo[buflen] = 0; /* just in case so the caller
3200 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003201 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 }
Steve French989c7e52009-05-02 05:32:20 +00003203
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003205 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
3207 /* Note: On -EAGAIN error only caller can retry on handle based calls
3208 since file handle passed in no longer valid */
3209
3210 return rc;
3211}
Steve Frenchc52a9552011-02-24 06:16:22 +00003212#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
3214#ifdef CONFIG_CIFS_POSIX
3215
3216/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003217static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3218 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219{
3220 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003221 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3222 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3223 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003224/*
3225 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3226 ace->e_perm, ace->e_tag, ace->e_id);
3227*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228
3229 return;
3230}
3231
3232/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003233static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3234 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235{
3236 int size = 0;
3237 int i;
3238 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003239 struct cifs_posix_ace *pACE;
3240 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3241 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
3243 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3244 return -EOPNOTSUPP;
3245
Steve French790fe572007-07-07 19:25:05 +00003246 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 count = le16_to_cpu(cifs_acl->access_entry_count);
3248 pACE = &cifs_acl->ace_array[0];
3249 size = sizeof(struct cifs_posix_acl);
3250 size += sizeof(struct cifs_posix_ace) * count;
3251 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003252 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003253 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3254 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 return -EINVAL;
3256 }
Steve French790fe572007-07-07 19:25:05 +00003257 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 count = le16_to_cpu(cifs_acl->access_entry_count);
3259 size = sizeof(struct cifs_posix_acl);
3260 size += sizeof(struct cifs_posix_ace) * count;
3261/* skip past access ACEs to get to default ACEs */
3262 pACE = &cifs_acl->ace_array[count];
3263 count = le16_to_cpu(cifs_acl->default_entry_count);
3264 size += sizeof(struct cifs_posix_ace) * count;
3265 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003266 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 return -EINVAL;
3268 } else {
3269 /* illegal type */
3270 return -EINVAL;
3271 }
3272
3273 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003274 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003275 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003276 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 return -ERANGE;
3278 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003279 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003280 for (i = 0; i < count ; i++) {
3281 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3282 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 }
3284 }
3285 return size;
3286}
3287
Steve French50c2f752007-07-13 00:33:32 +00003288static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3289 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290{
3291 __u16 rc = 0; /* 0 = ACL converted ok */
3292
Steve Frenchff7feac2005-11-15 16:45:16 -08003293 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3294 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003296 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 /* Probably no need to le convert -1 on any arch but can not hurt */
3298 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003299 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003300 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003301/*
3302 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3303 ace->e_perm, ace->e_tag, ace->e_id);
3304*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return rc;
3306}
3307
3308/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003309static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3310 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311{
3312 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003313 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3314 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 int count;
3316 int i;
3317
Steve French790fe572007-07-07 19:25:05 +00003318 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 return 0;
3320
3321 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003322 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3323 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003324 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003325 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3326 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 return 0;
3328 }
3329 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003330 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003331 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003332 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003333 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003335 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 return 0;
3337 }
Steve French50c2f752007-07-13 00:33:32 +00003338 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3340 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003341 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 /* ACE not converted */
3343 break;
3344 }
3345 }
Steve French790fe572007-07-07 19:25:05 +00003346 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3348 rc += sizeof(struct cifs_posix_acl);
3349 /* BB add check to make sure ACL does not overflow SMB */
3350 }
3351 return rc;
3352}
3353
3354int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003355CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003356 const unsigned char *searchName,
3357 char *acl_inf, const int buflen, const int acl_type,
3358 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359{
3360/* SMB_QUERY_POSIX_ACL */
3361 TRANSACTION2_QPI_REQ *pSMB = NULL;
3362 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3363 int rc = 0;
3364 int bytes_returned;
3365 int name_len;
3366 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003367
Joe Perchesf96637b2013-05-04 22:12:25 -05003368 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
3370queryAclRetry:
3371 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3372 (void **) &pSMBr);
3373 if (rc)
3374 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003375
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3377 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003378 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3379 searchName, PATH_MAX, nls_codepage,
3380 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 name_len++; /* trailing null */
3382 name_len *= 2;
3383 pSMB->FileName[name_len] = 0;
3384 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003385 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 name_len = strnlen(searchName, PATH_MAX);
3387 name_len++; /* trailing null */
3388 strncpy(pSMB->FileName, searchName, name_len);
3389 }
3390
3391 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3392 pSMB->TotalDataCount = 0;
3393 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003394 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 pSMB->MaxDataCount = cpu_to_le16(4000);
3396 pSMB->MaxSetupCount = 0;
3397 pSMB->Reserved = 0;
3398 pSMB->Flags = 0;
3399 pSMB->Timeout = 0;
3400 pSMB->Reserved2 = 0;
3401 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003402 offsetof(struct smb_com_transaction2_qpi_req,
3403 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 pSMB->DataCount = 0;
3405 pSMB->DataOffset = 0;
3406 pSMB->SetupCount = 1;
3407 pSMB->Reserved3 = 0;
3408 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3409 byte_count = params + 1 /* pad */ ;
3410 pSMB->TotalParameterCount = cpu_to_le16(params);
3411 pSMB->ParameterCount = pSMB->TotalParameterCount;
3412 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3413 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003414 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 pSMB->ByteCount = cpu_to_le16(byte_count);
3416
3417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3418 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003419 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003421 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 } else {
3423 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003424
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003427 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 rc = -EIO; /* bad smb */
3429 else {
3430 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3431 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3432 rc = cifs_copy_posix_acl(acl_inf,
3433 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003434 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 }
3436 }
3437 cifs_buf_release(pSMB);
3438 if (rc == -EAGAIN)
3439 goto queryAclRetry;
3440 return rc;
3441}
3442
3443int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003444CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003445 const unsigned char *fileName,
3446 const char *local_acl, const int buflen,
3447 const int acl_type,
3448 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449{
3450 struct smb_com_transaction2_spi_req *pSMB = NULL;
3451 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3452 char *parm_data;
3453 int name_len;
3454 int rc = 0;
3455 int bytes_returned = 0;
3456 __u16 params, byte_count, data_count, param_offset, offset;
3457
Joe Perchesf96637b2013-05-04 22:12:25 -05003458 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459setAclRetry:
3460 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003461 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 if (rc)
3463 return rc;
3464 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3465 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003466 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3467 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 name_len++; /* trailing null */
3469 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003470 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 name_len = strnlen(fileName, PATH_MAX);
3472 name_len++; /* trailing null */
3473 strncpy(pSMB->FileName, fileName, name_len);
3474 }
3475 params = 6 + name_len;
3476 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003477 /* BB find max SMB size from sess */
3478 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 pSMB->MaxSetupCount = 0;
3480 pSMB->Reserved = 0;
3481 pSMB->Flags = 0;
3482 pSMB->Timeout = 0;
3483 pSMB->Reserved2 = 0;
3484 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003485 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 offset = param_offset + params;
3487 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3488 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3489
3490 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003491 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
Steve French790fe572007-07-07 19:25:05 +00003493 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 rc = -EOPNOTSUPP;
3495 goto setACLerrorExit;
3496 }
3497 pSMB->DataOffset = cpu_to_le16(offset);
3498 pSMB->SetupCount = 1;
3499 pSMB->Reserved3 = 0;
3500 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3501 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3502 byte_count = 3 /* pad */ + params + data_count;
3503 pSMB->DataCount = cpu_to_le16(data_count);
3504 pSMB->TotalDataCount = pSMB->DataCount;
3505 pSMB->ParameterCount = cpu_to_le16(params);
3506 pSMB->TotalParameterCount = pSMB->ParameterCount;
3507 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003508 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 pSMB->ByteCount = cpu_to_le16(byte_count);
3510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003511 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003512 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003513 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
3515setACLerrorExit:
3516 cifs_buf_release(pSMB);
3517 if (rc == -EAGAIN)
3518 goto setAclRetry;
3519 return rc;
3520}
3521
Steve Frenchf654bac2005-04-28 22:41:04 -07003522/* BB fix tabs in this function FIXME BB */
3523int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003524CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003525 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003526{
Steve French50c2f752007-07-13 00:33:32 +00003527 int rc = 0;
3528 struct smb_t2_qfi_req *pSMB = NULL;
3529 struct smb_t2_qfi_rsp *pSMBr = NULL;
3530 int bytes_returned;
3531 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003532
Joe Perchesf96637b2013-05-04 22:12:25 -05003533 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003534 if (tcon == NULL)
3535 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003536
3537GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003538 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3539 (void **) &pSMBr);
3540 if (rc)
3541 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003542
Steve Frenchad7a2922008-02-07 23:25:02 +00003543 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003544 pSMB->t2.TotalDataCount = 0;
3545 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3546 /* BB find exact max data count below from sess structure BB */
3547 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3548 pSMB->t2.MaxSetupCount = 0;
3549 pSMB->t2.Reserved = 0;
3550 pSMB->t2.Flags = 0;
3551 pSMB->t2.Timeout = 0;
3552 pSMB->t2.Reserved2 = 0;
3553 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3554 Fid) - 4);
3555 pSMB->t2.DataCount = 0;
3556 pSMB->t2.DataOffset = 0;
3557 pSMB->t2.SetupCount = 1;
3558 pSMB->t2.Reserved3 = 0;
3559 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3560 byte_count = params + 1 /* pad */ ;
3561 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3562 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3563 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3564 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003565 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003566 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003567 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003568
Steve French790fe572007-07-07 19:25:05 +00003569 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3570 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3571 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003572 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003573 } else {
3574 /* decode response */
3575 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003576 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003577 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003578 /* If rc should we check for EOPNOSUPP and
3579 disable the srvino flag? or in caller? */
3580 rc = -EIO; /* bad smb */
3581 else {
3582 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3583 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3584 struct file_chattr_info *pfinfo;
3585 /* BB Do we need a cast or hash here ? */
3586 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003587 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003588 rc = -EIO;
3589 goto GetExtAttrOut;
3590 }
3591 pfinfo = (struct file_chattr_info *)
3592 (data_offset + (char *) &pSMBr->hdr.Protocol);
3593 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003594 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003595 }
3596 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003597GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003598 cifs_buf_release(pSMB);
3599 if (rc == -EAGAIN)
3600 goto GetExtAttrRetry;
3601 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003602}
3603
Steve Frenchf654bac2005-04-28 22:41:04 -07003604#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
Jeff Layton79df1ba2010-12-06 12:52:08 -05003606#ifdef CONFIG_CIFS_ACL
3607/*
3608 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3609 * all NT TRANSACTS that we init here have total parm and data under about 400
3610 * bytes (to fit in small cifs buffer size), which is the case so far, it
3611 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3612 * returned setup area) and MaxParameterCount (returned parms size) must be set
3613 * by caller
3614 */
3615static int
3616smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003617 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003618 void **ret_buf)
3619{
3620 int rc;
3621 __u32 temp_offset;
3622 struct smb_com_ntransact_req *pSMB;
3623
3624 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3625 (void **)&pSMB);
3626 if (rc)
3627 return rc;
3628 *ret_buf = (void *)pSMB;
3629 pSMB->Reserved = 0;
3630 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3631 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003632 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003633 pSMB->ParameterCount = pSMB->TotalParameterCount;
3634 pSMB->DataCount = pSMB->TotalDataCount;
3635 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3636 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3637 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3638 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3639 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3640 pSMB->SubCommand = cpu_to_le16(sub_command);
3641 return 0;
3642}
3643
3644static int
3645validate_ntransact(char *buf, char **ppparm, char **ppdata,
3646 __u32 *pparmlen, __u32 *pdatalen)
3647{
3648 char *end_of_smb;
3649 __u32 data_count, data_offset, parm_count, parm_offset;
3650 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003651 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003652
3653 *pdatalen = 0;
3654 *pparmlen = 0;
3655
3656 if (buf == NULL)
3657 return -EINVAL;
3658
3659 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3660
Jeff Layton820a8032011-05-04 08:05:26 -04003661 bcc = get_bcc(&pSMBr->hdr);
3662 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003663 (char *)&pSMBr->ByteCount;
3664
3665 data_offset = le32_to_cpu(pSMBr->DataOffset);
3666 data_count = le32_to_cpu(pSMBr->DataCount);
3667 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3668 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3669
3670 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3671 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3672
3673 /* should we also check that parm and data areas do not overlap? */
3674 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003675 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003676 return -EINVAL;
3677 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003678 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003679 return -EINVAL;
3680 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003681 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003682 return -EINVAL;
3683 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003684 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3685 *ppdata, data_count, (data_count + *ppdata),
3686 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003687 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003688 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003689 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003690 return -EINVAL;
3691 }
3692 *pdatalen = data_count;
3693 *pparmlen = parm_count;
3694 return 0;
3695}
3696
Steve French0a4b92c2006-01-12 15:44:21 -08003697/* Get Security Descriptor (by handle) from remote server for a file or dir */
3698int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003699CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003700 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003701{
3702 int rc = 0;
3703 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003704 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003705 struct kvec iov[1];
3706
Joe Perchesf96637b2013-05-04 22:12:25 -05003707 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003708
Steve French630f3f0c2007-10-25 21:17:17 +00003709 *pbuflen = 0;
3710 *acl_inf = NULL;
3711
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003712 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003713 8 /* parm len */, tcon, (void **) &pSMB);
3714 if (rc)
3715 return rc;
3716
3717 pSMB->MaxParameterCount = cpu_to_le32(4);
3718 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3719 pSMB->MaxSetupCount = 0;
3720 pSMB->Fid = fid; /* file handle always le */
3721 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3722 CIFS_ACL_DACL);
3723 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003724 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003725 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003726 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003727
Steve Frencha761ac52007-10-18 21:45:27 +00003728 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003729 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003730 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003731 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003732 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003733 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003734 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003735 __u32 parm_len;
3736 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003737 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003738 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003739
3740/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003741 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003742 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003743 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003744 goto qsec_out;
3745 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3746
Joe Perchesf96637b2013-05-04 22:12:25 -05003747 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3748 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003749
3750 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3751 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003752 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003753 goto qsec_out;
3754 }
3755
3756/* BB check that data area is minimum length and as big as acl_len */
3757
Steve Frenchaf6f4612007-10-16 18:40:37 +00003758 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003759 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003760 cifs_dbg(VFS, "acl length %d does not match %d\n",
3761 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003762 if (*pbuflen > acl_len)
3763 *pbuflen = acl_len;
3764 }
Steve French0a4b92c2006-01-12 15:44:21 -08003765
Steve French630f3f0c2007-10-25 21:17:17 +00003766 /* check if buffer is big enough for the acl
3767 header followed by the smallest SID */
3768 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3769 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003770 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003771 rc = -EINVAL;
3772 *pbuflen = 0;
3773 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003774 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003775 if (*acl_inf == NULL) {
3776 *pbuflen = 0;
3777 rc = -ENOMEM;
3778 }
Steve French630f3f0c2007-10-25 21:17:17 +00003779 }
Steve French0a4b92c2006-01-12 15:44:21 -08003780 }
3781qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003782 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003783 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003784 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003785 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003786/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003787 return rc;
3788}
Steve French97837582007-12-31 07:47:21 +00003789
3790int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003791CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003792 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003793{
3794 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3795 int rc = 0;
3796 int bytes_returned = 0;
3797 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003798 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003799
3800setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003801 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003802 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003803 return rc;
Steve French97837582007-12-31 07:47:21 +00003804
3805 pSMB->MaxSetupCount = 0;
3806 pSMB->Reserved = 0;
3807
3808 param_count = 8;
3809 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3810 data_count = acllen;
3811 data_offset = param_offset + param_count;
3812 byte_count = 3 /* pad */ + param_count;
3813
3814 pSMB->DataCount = cpu_to_le32(data_count);
3815 pSMB->TotalDataCount = pSMB->DataCount;
3816 pSMB->MaxParameterCount = cpu_to_le32(4);
3817 pSMB->MaxDataCount = cpu_to_le32(16384);
3818 pSMB->ParameterCount = cpu_to_le32(param_count);
3819 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3820 pSMB->TotalParameterCount = pSMB->ParameterCount;
3821 pSMB->DataOffset = cpu_to_le32(data_offset);
3822 pSMB->SetupCount = 0;
3823 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3824 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3825
3826 pSMB->Fid = fid; /* file handle always le */
3827 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003828 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003829
3830 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003831 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3832 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003833 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003834 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003835 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003836
3837 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3838 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3839
Joe Perchesf96637b2013-05-04 22:12:25 -05003840 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3841 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003842 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003843 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003844 cifs_buf_release(pSMB);
3845
3846 if (rc == -EAGAIN)
3847 goto setCifsAclRetry;
3848
3849 return (rc);
3850}
3851
Jeff Layton79df1ba2010-12-06 12:52:08 -05003852#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003853
Steve French6b8edfe2005-08-23 20:26:03 -07003854/* Legacy Query Path Information call for lookup to old servers such
3855 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003856int
3857SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3858 const char *search_name, FILE_ALL_INFO *data,
3859 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003860{
Steve Frenchad7a2922008-02-07 23:25:02 +00003861 QUERY_INFORMATION_REQ *pSMB;
3862 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003863 int rc = 0;
3864 int bytes_returned;
3865 int name_len;
3866
Joe Perchesf96637b2013-05-04 22:12:25 -05003867 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003868QInfRetry:
3869 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003870 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003871 if (rc)
3872 return rc;
3873
3874 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3875 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003876 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003877 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003878 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003879 name_len++; /* trailing null */
3880 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003881 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003882 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003883 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003884 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003885 }
3886 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003887 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003888 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003889 pSMB->ByteCount = cpu_to_le16(name_len);
3890
3891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003893 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003894 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003895 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003896 struct timespec ts;
3897 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003898
3899 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003900 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003901 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003902 ts.tv_nsec = 0;
3903 ts.tv_sec = time;
3904 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003905 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3906 data->LastWriteTime = data->ChangeTime;
3907 data->LastAccessTime = 0;
3908 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003909 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003910 data->EndOfFile = data->AllocationSize;
3911 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003912 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003913 } else
3914 rc = -EIO; /* bad buffer passed in */
3915
3916 cifs_buf_release(pSMB);
3917
3918 if (rc == -EAGAIN)
3919 goto QInfRetry;
3920
3921 return rc;
3922}
3923
Jeff Laytonbcd53572010-02-12 07:44:16 -05003924int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003925CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003926 u16 netfid, FILE_ALL_INFO *pFindData)
3927{
3928 struct smb_t2_qfi_req *pSMB = NULL;
3929 struct smb_t2_qfi_rsp *pSMBr = NULL;
3930 int rc = 0;
3931 int bytes_returned;
3932 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003933
Jeff Laytonbcd53572010-02-12 07:44:16 -05003934QFileInfoRetry:
3935 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3936 (void **) &pSMBr);
3937 if (rc)
3938 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003939
Jeff Laytonbcd53572010-02-12 07:44:16 -05003940 params = 2 /* level */ + 2 /* fid */;
3941 pSMB->t2.TotalDataCount = 0;
3942 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3943 /* BB find exact max data count below from sess structure BB */
3944 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3945 pSMB->t2.MaxSetupCount = 0;
3946 pSMB->t2.Reserved = 0;
3947 pSMB->t2.Flags = 0;
3948 pSMB->t2.Timeout = 0;
3949 pSMB->t2.Reserved2 = 0;
3950 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3951 Fid) - 4);
3952 pSMB->t2.DataCount = 0;
3953 pSMB->t2.DataOffset = 0;
3954 pSMB->t2.SetupCount = 1;
3955 pSMB->t2.Reserved3 = 0;
3956 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3957 byte_count = params + 1 /* pad */ ;
3958 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3959 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3960 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3961 pSMB->Pad = 0;
3962 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003963 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003964
3965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3967 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003968 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003969 } else { /* decode response */
3970 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3971
3972 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3973 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003974 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003975 rc = -EIO; /* bad smb */
3976 else if (pFindData) {
3977 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3978 memcpy((char *) pFindData,
3979 (char *) &pSMBr->hdr.Protocol +
3980 data_offset, sizeof(FILE_ALL_INFO));
3981 } else
3982 rc = -ENOMEM;
3983 }
3984 cifs_buf_release(pSMB);
3985 if (rc == -EAGAIN)
3986 goto QFileInfoRetry;
3987
3988 return rc;
3989}
Steve French6b8edfe2005-08-23 20:26:03 -07003990
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003992CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003993 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003994 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003995 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003997 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 TRANSACTION2_QPI_REQ *pSMB = NULL;
3999 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4000 int rc = 0;
4001 int bytes_returned;
4002 int name_len;
4003 __u16 params, byte_count;
4004
Joe Perchesf96637b2013-05-04 22:12:25 -05004005 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006QPathInfoRetry:
4007 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4008 (void **) &pSMBr);
4009 if (rc)
4010 return rc;
4011
4012 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4013 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004014 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004015 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 name_len++; /* trailing null */
4017 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004018 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004019 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004021 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 }
4023
Steve French50c2f752007-07-13 00:33:32 +00004024 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 pSMB->TotalDataCount = 0;
4026 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004027 /* BB find exact max SMB PDU from sess structure BB */
4028 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 pSMB->MaxSetupCount = 0;
4030 pSMB->Reserved = 0;
4031 pSMB->Flags = 0;
4032 pSMB->Timeout = 0;
4033 pSMB->Reserved2 = 0;
4034 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004035 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 pSMB->DataCount = 0;
4037 pSMB->DataOffset = 0;
4038 pSMB->SetupCount = 1;
4039 pSMB->Reserved3 = 0;
4040 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4041 byte_count = params + 1 /* pad */ ;
4042 pSMB->TotalParameterCount = cpu_to_le16(params);
4043 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004044 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004045 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4046 else
4047 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004049 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 pSMB->ByteCount = cpu_to_le16(byte_count);
4051
4052 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4053 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4054 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004055 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 } else { /* decode response */
4057 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4058
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004059 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4060 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004061 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004063 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004064 rc = -EIO; /* 24 or 26 expected but we do not read
4065 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004066 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004067 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004069
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004070 /*
4071 * On legacy responses we do not read the last field,
4072 * EAsize, fortunately since it varies by subdialect and
4073 * also note it differs on Set vs Get, ie two bytes or 4
4074 * bytes depending but we don't care here.
4075 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004076 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004077 size = sizeof(FILE_INFO_STANDARD);
4078 else
4079 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004080 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004081 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 } else
4083 rc = -ENOMEM;
4084 }
4085 cifs_buf_release(pSMB);
4086 if (rc == -EAGAIN)
4087 goto QPathInfoRetry;
4088
4089 return rc;
4090}
4091
4092int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004093CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004094 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4095{
4096 struct smb_t2_qfi_req *pSMB = NULL;
4097 struct smb_t2_qfi_rsp *pSMBr = NULL;
4098 int rc = 0;
4099 int bytes_returned;
4100 __u16 params, byte_count;
4101
4102UnixQFileInfoRetry:
4103 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4104 (void **) &pSMBr);
4105 if (rc)
4106 return rc;
4107
4108 params = 2 /* level */ + 2 /* fid */;
4109 pSMB->t2.TotalDataCount = 0;
4110 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4111 /* BB find exact max data count below from sess structure BB */
4112 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4113 pSMB->t2.MaxSetupCount = 0;
4114 pSMB->t2.Reserved = 0;
4115 pSMB->t2.Flags = 0;
4116 pSMB->t2.Timeout = 0;
4117 pSMB->t2.Reserved2 = 0;
4118 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4119 Fid) - 4);
4120 pSMB->t2.DataCount = 0;
4121 pSMB->t2.DataOffset = 0;
4122 pSMB->t2.SetupCount = 1;
4123 pSMB->t2.Reserved3 = 0;
4124 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4125 byte_count = params + 1 /* pad */ ;
4126 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4127 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4128 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4129 pSMB->Pad = 0;
4130 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004131 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004132
4133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4135 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004136 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004137 } else { /* decode response */
4138 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4139
Jeff Layton820a8032011-05-04 08:05:26 -04004140 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004141 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 -05004142 rc = -EIO; /* bad smb */
4143 } else {
4144 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4145 memcpy((char *) pFindData,
4146 (char *) &pSMBr->hdr.Protocol +
4147 data_offset,
4148 sizeof(FILE_UNIX_BASIC_INFO));
4149 }
4150 }
4151
4152 cifs_buf_release(pSMB);
4153 if (rc == -EAGAIN)
4154 goto UnixQFileInfoRetry;
4155
4156 return rc;
4157}
4158
4159int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004160CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004162 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004163 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164{
4165/* SMB_QUERY_FILE_UNIX_BASIC */
4166 TRANSACTION2_QPI_REQ *pSMB = NULL;
4167 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4168 int rc = 0;
4169 int bytes_returned = 0;
4170 int name_len;
4171 __u16 params, byte_count;
4172
Joe Perchesf96637b2013-05-04 22:12:25 -05004173 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174UnixQPathInfoRetry:
4175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4176 (void **) &pSMBr);
4177 if (rc)
4178 return rc;
4179
4180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4181 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004182 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4183 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 name_len++; /* trailing null */
4185 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004186 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 name_len = strnlen(searchName, PATH_MAX);
4188 name_len++; /* trailing null */
4189 strncpy(pSMB->FileName, searchName, name_len);
4190 }
4191
Steve French50c2f752007-07-13 00:33:32 +00004192 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 pSMB->TotalDataCount = 0;
4194 pSMB->MaxParameterCount = cpu_to_le16(2);
4195 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004196 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 pSMB->MaxSetupCount = 0;
4198 pSMB->Reserved = 0;
4199 pSMB->Flags = 0;
4200 pSMB->Timeout = 0;
4201 pSMB->Reserved2 = 0;
4202 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004203 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 pSMB->DataCount = 0;
4205 pSMB->DataOffset = 0;
4206 pSMB->SetupCount = 1;
4207 pSMB->Reserved3 = 0;
4208 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4209 byte_count = params + 1 /* pad */ ;
4210 pSMB->TotalParameterCount = cpu_to_le16(params);
4211 pSMB->ParameterCount = pSMB->TotalParameterCount;
4212 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4213 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004214 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 pSMB->ByteCount = cpu_to_le16(byte_count);
4216
4217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4219 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004220 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 } else { /* decode response */
4222 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4223
Jeff Layton820a8032011-05-04 08:05:26 -04004224 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004225 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 -07004226 rc = -EIO; /* bad smb */
4227 } else {
4228 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4229 memcpy((char *) pFindData,
4230 (char *) &pSMBr->hdr.Protocol +
4231 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004232 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 }
4234 }
4235 cifs_buf_release(pSMB);
4236 if (rc == -EAGAIN)
4237 goto UnixQPathInfoRetry;
4238
4239 return rc;
4240}
4241
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242/* xid, tcon, searchName and codepage are input parms, rest are returned */
4243int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004244CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004245 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004246 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004247 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248{
4249/* level 257 SMB_ */
4250 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4251 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004252 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 int rc = 0;
4254 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004255 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004257 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
Joe Perchesf96637b2013-05-04 22:12:25 -05004259 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
4261findFirstRetry:
4262 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4263 (void **) &pSMBr);
4264 if (rc)
4265 return rc;
4266
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004267 nls_codepage = cifs_sb->local_nls;
4268 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4269
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4271 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004272 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4273 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004274 /* We can not add the asterik earlier in case
4275 it got remapped to 0xF03A as if it were part of the
4276 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004278 if (msearch) {
4279 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4280 pSMB->FileName[name_len+1] = 0;
4281 pSMB->FileName[name_len+2] = '*';
4282 pSMB->FileName[name_len+3] = 0;
4283 name_len += 4; /* now the trailing null */
4284 /* null terminate just in case */
4285 pSMB->FileName[name_len] = 0;
4286 pSMB->FileName[name_len+1] = 0;
4287 name_len += 2;
4288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 } else { /* BB add check for overrun of SMB buf BB */
4290 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004292 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 free buffer exit; BB */
4294 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004295 if (msearch) {
4296 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4297 pSMB->FileName[name_len+1] = '*';
4298 pSMB->FileName[name_len+2] = 0;
4299 name_len += 3;
4300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 }
4302
4303 params = 12 + name_len /* includes null */ ;
4304 pSMB->TotalDataCount = 0; /* no EAs */
4305 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004306 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 pSMB->MaxSetupCount = 0;
4308 pSMB->Reserved = 0;
4309 pSMB->Flags = 0;
4310 pSMB->Timeout = 0;
4311 pSMB->Reserved2 = 0;
4312 byte_count = params + 1 /* pad */ ;
4313 pSMB->TotalParameterCount = cpu_to_le16(params);
4314 pSMB->ParameterCount = pSMB->TotalParameterCount;
4315 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004316 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4317 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 pSMB->DataCount = 0;
4319 pSMB->DataOffset = 0;
4320 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4321 pSMB->Reserved3 = 0;
4322 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4323 pSMB->SearchAttributes =
4324 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4325 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004326 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004327 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4329
4330 /* BB what should we set StorageType to? Does it matter? BB */
4331 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004332 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 pSMB->ByteCount = cpu_to_le16(byte_count);
4334
4335 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4336 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004337 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
Steve French88274812006-03-09 22:21:45 +00004339 if (rc) {/* BB add logic to retry regular search if Unix search
4340 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004342 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004343
Steve French88274812006-03-09 22:21:45 +00004344 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345
4346 /* BB eventually could optimize out free and realloc of buf */
4347 /* for this case */
4348 if (rc == -EAGAIN)
4349 goto findFirstRetry;
4350 } else { /* decode response */
4351 /* BB remember to free buffer if error BB */
4352 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004353 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004354 unsigned int lnoff;
4355
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004357 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 else
Steve French4b18f2a2008-04-29 00:06:05 +00004359 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
4361 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004362 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004363 psrch_inf->srch_entries_start =
4364 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4367 le16_to_cpu(pSMBr->t2.ParameterOffset));
4368
Steve French790fe572007-07-07 19:25:05 +00004369 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004370 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 else
Steve French4b18f2a2008-04-29 00:06:05 +00004372 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373
Steve French50c2f752007-07-13 00:33:32 +00004374 psrch_inf->entries_in_buffer =
4375 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004376 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004378 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004379 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004380 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004381 psrch_inf->last_entry = NULL;
4382 return rc;
4383 }
4384
Steve French0752f152008-10-07 20:03:33 +00004385 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004386 lnoff;
4387
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004388 if (pnetfid)
4389 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 } else {
4391 cifs_buf_release(pSMB);
4392 }
4393 }
4394
4395 return rc;
4396}
4397
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004398int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4399 __u16 searchHandle, __u16 search_flags,
4400 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401{
4402 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4403 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004404 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 char *response_data;
4406 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004407 int bytes_returned;
4408 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 __u16 params, byte_count;
4410
Joe Perchesf96637b2013-05-04 22:12:25 -05004411 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412
Steve French4b18f2a2008-04-29 00:06:05 +00004413 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 return -ENOENT;
4415
4416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4417 (void **) &pSMBr);
4418 if (rc)
4419 return rc;
4420
Steve French50c2f752007-07-13 00:33:32 +00004421 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 byte_count = 0;
4423 pSMB->TotalDataCount = 0; /* no EAs */
4424 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004425 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 pSMB->MaxSetupCount = 0;
4427 pSMB->Reserved = 0;
4428 pSMB->Flags = 0;
4429 pSMB->Timeout = 0;
4430 pSMB->Reserved2 = 0;
4431 pSMB->ParameterOffset = cpu_to_le16(
4432 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4433 pSMB->DataCount = 0;
4434 pSMB->DataOffset = 0;
4435 pSMB->SetupCount = 1;
4436 pSMB->Reserved3 = 0;
4437 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4438 pSMB->SearchHandle = searchHandle; /* always kept as le */
4439 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004440 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4442 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004443 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444
4445 name_len = psrch_inf->resume_name_len;
4446 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004447 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4449 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004450 /* 14 byte parm len above enough for 2 byte null terminator */
4451 pSMB->ResumeFileName[name_len] = 0;
4452 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 } else {
4454 rc = -EINVAL;
4455 goto FNext2_err_exit;
4456 }
4457 byte_count = params + 1 /* pad */ ;
4458 pSMB->TotalParameterCount = cpu_to_le16(params);
4459 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004460 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004462
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4464 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004465 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 if (rc) {
4467 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004468 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004469 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004470 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004472 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 } else { /* decode response */
4474 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004475
Steve French790fe572007-07-07 19:25:05 +00004476 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004477 unsigned int lnoff;
4478
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 /* BB fixme add lock for file (srch_info) struct here */
4480 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004481 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 else
Steve French4b18f2a2008-04-29 00:06:05 +00004483 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 response_data = (char *) &pSMBr->hdr.Protocol +
4485 le16_to_cpu(pSMBr->t2.ParameterOffset);
4486 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4487 response_data = (char *)&pSMBr->hdr.Protocol +
4488 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004489 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004490 cifs_small_buf_release(
4491 psrch_inf->ntwrk_buf_start);
4492 else
4493 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 psrch_inf->srch_entries_start = response_data;
4495 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004496 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004497 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004498 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 else
Steve French4b18f2a2008-04-29 00:06:05 +00004500 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004501 psrch_inf->entries_in_buffer =
4502 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 psrch_inf->index_of_last_entry +=
4504 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004505 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004506 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004507 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004508 psrch_inf->last_entry = NULL;
4509 return rc;
4510 } else
4511 psrch_inf->last_entry =
4512 psrch_inf->srch_entries_start + lnoff;
4513
Joe Perchesf96637b2013-05-04 22:12:25 -05004514/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4515 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516
4517 /* BB fixme add unlock here */
4518 }
4519
4520 }
4521
4522 /* BB On error, should we leave previous search buf (and count and
4523 last entry fields) intact or free the previous one? */
4524
4525 /* Note: On -EAGAIN error only caller can retry on handle based calls
4526 since file handle passed in no longer valid */
4527FNext2_err_exit:
4528 if (rc != 0)
4529 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 return rc;
4531}
4532
4533int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004534CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004535 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536{
4537 int rc = 0;
4538 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539
Joe Perchesf96637b2013-05-04 22:12:25 -05004540 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4542
4543 /* no sense returning error if session restarted
4544 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004545 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 return 0;
4547 if (rc)
4548 return rc;
4549
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 pSMB->FileID = searchHandle;
4551 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004552 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004553 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004554 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004555
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004556 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557
4558 /* Since session is dead, search handle closed on server already */
4559 if (rc == -EAGAIN)
4560 rc = 0;
4561
4562 return rc;
4563}
4564
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004566CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004567 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004568 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569{
4570 int rc = 0;
4571 TRANSACTION2_QPI_REQ *pSMB = NULL;
4572 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4573 int name_len, bytes_returned;
4574 __u16 params, byte_count;
4575
Joe Perchesf96637b2013-05-04 22:12:25 -05004576 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004577 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004578 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579
4580GetInodeNumberRetry:
4581 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004582 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 if (rc)
4584 return rc;
4585
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4587 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004588 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004589 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004590 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 name_len++; /* trailing null */
4592 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004593 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004594 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004596 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 }
4598
4599 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4600 pSMB->TotalDataCount = 0;
4601 pSMB->MaxParameterCount = cpu_to_le16(2);
4602 /* BB find exact max data count below from sess structure BB */
4603 pSMB->MaxDataCount = cpu_to_le16(4000);
4604 pSMB->MaxSetupCount = 0;
4605 pSMB->Reserved = 0;
4606 pSMB->Flags = 0;
4607 pSMB->Timeout = 0;
4608 pSMB->Reserved2 = 0;
4609 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004610 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 pSMB->DataCount = 0;
4612 pSMB->DataOffset = 0;
4613 pSMB->SetupCount = 1;
4614 pSMB->Reserved3 = 0;
4615 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4616 byte_count = params + 1 /* pad */ ;
4617 pSMB->TotalParameterCount = cpu_to_le16(params);
4618 pSMB->ParameterCount = pSMB->TotalParameterCount;
4619 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4620 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004621 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 pSMB->ByteCount = cpu_to_le16(byte_count);
4623
4624 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4625 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4626 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004627 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 } else {
4629 /* decode response */
4630 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004632 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 /* If rc should we check for EOPNOSUPP and
4634 disable the srvino flag? or in caller? */
4635 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004636 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4638 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004639 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004641 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004642 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 rc = -EIO;
4644 goto GetInodeNumOut;
4645 }
4646 pfinfo = (struct file_internal_info *)
4647 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004648 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
4650 }
4651GetInodeNumOut:
4652 cifs_buf_release(pSMB);
4653 if (rc == -EAGAIN)
4654 goto GetInodeNumberRetry;
4655 return rc;
4656}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
Igor Mammedovfec45852008-05-16 13:06:30 +04004658/* parses DFS refferal V3 structure
4659 * caller is responsible for freeing target_nodes
4660 * returns:
4661 * on success - 0
4662 * on failure - errno
4663 */
4664static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004665parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004666 unsigned int *num_of_nodes,
4667 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004668 const struct nls_table *nls_codepage, int remap,
4669 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004670{
4671 int i, rc = 0;
4672 char *data_end;
4673 bool is_unicode;
4674 struct dfs_referral_level_3 *ref;
4675
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004676 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4677 is_unicode = true;
4678 else
4679 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004680 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4681
4682 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004683 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4684 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004686 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004687 }
4688
4689 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004690 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004691 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4692 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004693 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004694 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004695 }
4696
4697 /* get the upper boundary of the resp buffer */
4698 data_end = (char *)(&(pSMBr->PathConsumed)) +
4699 le16_to_cpu(pSMBr->t2.DataCount);
4700
Joe Perchesf96637b2013-05-04 22:12:25 -05004701 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4702 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004703
Joe Perchesf96637b2013-05-04 22:12:25 -05004704 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4705 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004706 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004707 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004708 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004709 }
4710
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004711 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004712 for (i = 0; i < *num_of_nodes; i++) {
4713 char *temp;
4714 int max_len;
4715 struct dfs_info3_param *node = (*target_nodes)+i;
4716
Steve French0e0d2cf2009-05-01 05:27:32 +00004717 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004718 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004719 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4720 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004721 if (tmp == NULL) {
4722 rc = -ENOMEM;
4723 goto parse_DFS_referrals_exit;
4724 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004725 cifsConvertToUTF16((__le16 *) tmp, searchName,
4726 PATH_MAX, nls_codepage, remap);
4727 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004728 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004729 nls_codepage);
4730 kfree(tmp);
4731 } else
4732 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4733
Igor Mammedovfec45852008-05-16 13:06:30 +04004734 node->server_type = le16_to_cpu(ref->ServerType);
4735 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4736
4737 /* copy DfsPath */
4738 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4739 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004740 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4741 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004742 if (!node->path_name) {
4743 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004744 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004745 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004746
4747 /* copy link target UNC */
4748 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4749 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004750 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4751 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004752 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004753 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004754 goto parse_DFS_referrals_exit;
4755 }
4756
4757 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004758 }
4759
Steve Frencha1fe78f2008-05-16 18:48:38 +00004760parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004761 if (rc) {
4762 free_dfs_info_array(*target_nodes, *num_of_nodes);
4763 *target_nodes = NULL;
4764 *num_of_nodes = 0;
4765 }
4766 return rc;
4767}
4768
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004770CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004771 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004772 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004773 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774{
4775/* TRANS2_GET_DFS_REFERRAL */
4776 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4777 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 int rc = 0;
4779 int bytes_returned;
4780 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004782 *num_of_nodes = 0;
4783 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784
Joe Perchesf96637b2013-05-04 22:12:25 -05004785 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 if (ses == NULL)
4787 return -ENODEV;
4788getDFSRetry:
4789 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4790 (void **) &pSMBr);
4791 if (rc)
4792 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004793
4794 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004795 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004796 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->hdr.Tid = ses->ipc_tid;
4798 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004799 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004801 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
4804 if (ses->capabilities & CAP_UNICODE) {
4805 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4806 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004807 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004808 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004809 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 name_len++; /* trailing null */
4811 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004812 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004813 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004815 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 }
4817
Steve French790fe572007-07-07 19:25:05 +00004818 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004819 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004820 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4821 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4822 }
4823
Steve French50c2f752007-07-13 00:33:32 +00004824 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004825
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 params = 2 /* level */ + name_len /*includes null */ ;
4827 pSMB->TotalDataCount = 0;
4828 pSMB->DataCount = 0;
4829 pSMB->DataOffset = 0;
4830 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004831 /* BB find exact max SMB PDU from sess structure BB */
4832 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 pSMB->MaxSetupCount = 0;
4834 pSMB->Reserved = 0;
4835 pSMB->Flags = 0;
4836 pSMB->Timeout = 0;
4837 pSMB->Reserved2 = 0;
4838 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004839 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 pSMB->SetupCount = 1;
4841 pSMB->Reserved3 = 0;
4842 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4843 byte_count = params + 3 /* pad */ ;
4844 pSMB->ParameterCount = cpu_to_le16(params);
4845 pSMB->TotalParameterCount = pSMB->ParameterCount;
4846 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004847 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 pSMB->ByteCount = cpu_to_le16(byte_count);
4849
4850 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4852 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004853 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004854 goto GetDFSRefExit;
4855 }
4856 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004858 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004859 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004860 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004861 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004863
Joe Perchesf96637b2013-05-04 22:12:25 -05004864 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4865 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004866
4867 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004868 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004869 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004870 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004871
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004873 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874
4875 if (rc == -EAGAIN)
4876 goto getDFSRetry;
4877
4878 return rc;
4879}
4880
Steve French20962432005-09-21 22:05:57 -07004881/* Query File System Info such as free space to old servers such as Win 9x */
4882int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004883SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4884 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004885{
4886/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4887 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4888 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4889 FILE_SYSTEM_ALLOC_INFO *response_data;
4890 int rc = 0;
4891 int bytes_returned = 0;
4892 __u16 params, byte_count;
4893
Joe Perchesf96637b2013-05-04 22:12:25 -05004894 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004895oldQFSInfoRetry:
4896 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4897 (void **) &pSMBr);
4898 if (rc)
4899 return rc;
Steve French20962432005-09-21 22:05:57 -07004900
4901 params = 2; /* level */
4902 pSMB->TotalDataCount = 0;
4903 pSMB->MaxParameterCount = cpu_to_le16(2);
4904 pSMB->MaxDataCount = cpu_to_le16(1000);
4905 pSMB->MaxSetupCount = 0;
4906 pSMB->Reserved = 0;
4907 pSMB->Flags = 0;
4908 pSMB->Timeout = 0;
4909 pSMB->Reserved2 = 0;
4910 byte_count = params + 1 /* pad */ ;
4911 pSMB->TotalParameterCount = cpu_to_le16(params);
4912 pSMB->ParameterCount = pSMB->TotalParameterCount;
4913 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4914 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4915 pSMB->DataCount = 0;
4916 pSMB->DataOffset = 0;
4917 pSMB->SetupCount = 1;
4918 pSMB->Reserved3 = 0;
4919 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4920 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004921 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004922 pSMB->ByteCount = cpu_to_le16(byte_count);
4923
4924 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4925 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4926 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004927 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004928 } else { /* decode response */
4929 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4930
Jeff Layton820a8032011-05-04 08:05:26 -04004931 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004932 rc = -EIO; /* bad smb */
4933 else {
4934 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004935 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004936 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004937
Steve French50c2f752007-07-13 00:33:32 +00004938 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004939 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4940 FSData->f_bsize =
4941 le16_to_cpu(response_data->BytesPerSector) *
4942 le32_to_cpu(response_data->
4943 SectorsPerAllocationUnit);
4944 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004945 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004946 FSData->f_bfree = FSData->f_bavail =
4947 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004948 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4949 (unsigned long long)FSData->f_blocks,
4950 (unsigned long long)FSData->f_bfree,
4951 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004952 }
4953 }
4954 cifs_buf_release(pSMB);
4955
4956 if (rc == -EAGAIN)
4957 goto oldQFSInfoRetry;
4958
4959 return rc;
4960}
4961
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004963CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4964 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965{
4966/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4967 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4968 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4969 FILE_SYSTEM_INFO *response_data;
4970 int rc = 0;
4971 int bytes_returned = 0;
4972 __u16 params, byte_count;
4973
Joe Perchesf96637b2013-05-04 22:12:25 -05004974 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975QFSInfoRetry:
4976 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4977 (void **) &pSMBr);
4978 if (rc)
4979 return rc;
4980
4981 params = 2; /* level */
4982 pSMB->TotalDataCount = 0;
4983 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004984 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 pSMB->MaxSetupCount = 0;
4986 pSMB->Reserved = 0;
4987 pSMB->Flags = 0;
4988 pSMB->Timeout = 0;
4989 pSMB->Reserved2 = 0;
4990 byte_count = params + 1 /* pad */ ;
4991 pSMB->TotalParameterCount = cpu_to_le16(params);
4992 pSMB->ParameterCount = pSMB->TotalParameterCount;
4993 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004994 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 pSMB->DataCount = 0;
4996 pSMB->DataOffset = 0;
4997 pSMB->SetupCount = 1;
4998 pSMB->Reserved3 = 0;
4999 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5000 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005001 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 pSMB->ByteCount = cpu_to_le16(byte_count);
5003
5004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5006 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005007 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005009 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010
Jeff Layton820a8032011-05-04 08:05:26 -04005011 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 rc = -EIO; /* bad smb */
5013 else {
5014 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015
5016 response_data =
5017 (FILE_SYSTEM_INFO
5018 *) (((char *) &pSMBr->hdr.Protocol) +
5019 data_offset);
5020 FSData->f_bsize =
5021 le32_to_cpu(response_data->BytesPerSector) *
5022 le32_to_cpu(response_data->
5023 SectorsPerAllocationUnit);
5024 FSData->f_blocks =
5025 le64_to_cpu(response_data->TotalAllocationUnits);
5026 FSData->f_bfree = FSData->f_bavail =
5027 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005028 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5029 (unsigned long long)FSData->f_blocks,
5030 (unsigned long long)FSData->f_bfree,
5031 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032 }
5033 }
5034 cifs_buf_release(pSMB);
5035
5036 if (rc == -EAGAIN)
5037 goto QFSInfoRetry;
5038
5039 return rc;
5040}
5041
5042int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005043CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044{
5045/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5046 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5047 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5048 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5049 int rc = 0;
5050 int bytes_returned = 0;
5051 __u16 params, byte_count;
5052
Joe Perchesf96637b2013-05-04 22:12:25 -05005053 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054QFSAttributeRetry:
5055 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5056 (void **) &pSMBr);
5057 if (rc)
5058 return rc;
5059
5060 params = 2; /* level */
5061 pSMB->TotalDataCount = 0;
5062 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005063 /* BB find exact max SMB PDU from sess structure BB */
5064 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 pSMB->MaxSetupCount = 0;
5066 pSMB->Reserved = 0;
5067 pSMB->Flags = 0;
5068 pSMB->Timeout = 0;
5069 pSMB->Reserved2 = 0;
5070 byte_count = params + 1 /* pad */ ;
5071 pSMB->TotalParameterCount = cpu_to_le16(params);
5072 pSMB->ParameterCount = pSMB->TotalParameterCount;
5073 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005074 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 pSMB->DataCount = 0;
5076 pSMB->DataOffset = 0;
5077 pSMB->SetupCount = 1;
5078 pSMB->Reserved3 = 0;
5079 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5080 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005081 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 pSMB->ByteCount = cpu_to_le16(byte_count);
5083
5084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5086 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005087 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 } else { /* decode response */
5089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5090
Jeff Layton820a8032011-05-04 08:05:26 -04005091 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005092 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 rc = -EIO; /* bad smb */
5094 } else {
5095 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5096 response_data =
5097 (FILE_SYSTEM_ATTRIBUTE_INFO
5098 *) (((char *) &pSMBr->hdr.Protocol) +
5099 data_offset);
5100 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005101 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 }
5103 }
5104 cifs_buf_release(pSMB);
5105
5106 if (rc == -EAGAIN)
5107 goto QFSAttributeRetry;
5108
5109 return rc;
5110}
5111
5112int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005113CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114{
5115/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5116 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5117 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5118 FILE_SYSTEM_DEVICE_INFO *response_data;
5119 int rc = 0;
5120 int bytes_returned = 0;
5121 __u16 params, byte_count;
5122
Joe Perchesf96637b2013-05-04 22:12:25 -05005123 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124QFSDeviceRetry:
5125 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5126 (void **) &pSMBr);
5127 if (rc)
5128 return rc;
5129
5130 params = 2; /* level */
5131 pSMB->TotalDataCount = 0;
5132 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005133 /* BB find exact max SMB PDU from sess structure BB */
5134 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 pSMB->MaxSetupCount = 0;
5136 pSMB->Reserved = 0;
5137 pSMB->Flags = 0;
5138 pSMB->Timeout = 0;
5139 pSMB->Reserved2 = 0;
5140 byte_count = params + 1 /* pad */ ;
5141 pSMB->TotalParameterCount = cpu_to_le16(params);
5142 pSMB->ParameterCount = pSMB->TotalParameterCount;
5143 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005144 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145
5146 pSMB->DataCount = 0;
5147 pSMB->DataOffset = 0;
5148 pSMB->SetupCount = 1;
5149 pSMB->Reserved3 = 0;
5150 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5151 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005152 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 pSMB->ByteCount = cpu_to_le16(byte_count);
5154
5155 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5156 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5157 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005158 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 } else { /* decode response */
5160 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5161
Jeff Layton820a8032011-05-04 08:05:26 -04005162 if (rc || get_bcc(&pSMBr->hdr) <
5163 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 rc = -EIO; /* bad smb */
5165 else {
5166 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5167 response_data =
Steve French737b7582005-04-28 22:41:06 -07005168 (FILE_SYSTEM_DEVICE_INFO *)
5169 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 data_offset);
5171 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005172 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 }
5174 }
5175 cifs_buf_release(pSMB);
5176
5177 if (rc == -EAGAIN)
5178 goto QFSDeviceRetry;
5179
5180 return rc;
5181}
5182
5183int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005184CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185{
5186/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5187 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5188 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5189 FILE_SYSTEM_UNIX_INFO *response_data;
5190 int rc = 0;
5191 int bytes_returned = 0;
5192 __u16 params, byte_count;
5193
Joe Perchesf96637b2013-05-04 22:12:25 -05005194 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005196 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5197 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 if (rc)
5199 return rc;
5200
5201 params = 2; /* level */
5202 pSMB->TotalDataCount = 0;
5203 pSMB->DataCount = 0;
5204 pSMB->DataOffset = 0;
5205 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005206 /* BB find exact max SMB PDU from sess structure BB */
5207 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 pSMB->MaxSetupCount = 0;
5209 pSMB->Reserved = 0;
5210 pSMB->Flags = 0;
5211 pSMB->Timeout = 0;
5212 pSMB->Reserved2 = 0;
5213 byte_count = params + 1 /* pad */ ;
5214 pSMB->ParameterCount = cpu_to_le16(params);
5215 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005216 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5217 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 pSMB->SetupCount = 1;
5219 pSMB->Reserved3 = 0;
5220 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5221 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005222 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 pSMB->ByteCount = cpu_to_le16(byte_count);
5224
5225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5227 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005228 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 } else { /* decode response */
5230 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5231
Jeff Layton820a8032011-05-04 08:05:26 -04005232 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 rc = -EIO; /* bad smb */
5234 } else {
5235 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5236 response_data =
5237 (FILE_SYSTEM_UNIX_INFO
5238 *) (((char *) &pSMBr->hdr.Protocol) +
5239 data_offset);
5240 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005241 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 }
5243 }
5244 cifs_buf_release(pSMB);
5245
5246 if (rc == -EAGAIN)
5247 goto QFSUnixRetry;
5248
5249
5250 return rc;
5251}
5252
Jeremy Allisonac670552005-06-22 17:26:35 -07005253int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005254CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005255{
5256/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5257 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5258 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5259 int rc = 0;
5260 int bytes_returned = 0;
5261 __u16 params, param_offset, offset, byte_count;
5262
Joe Perchesf96637b2013-05-04 22:12:25 -05005263 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005264SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005265 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005266 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5267 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005268 if (rc)
5269 return rc;
5270
5271 params = 4; /* 2 bytes zero followed by info level. */
5272 pSMB->MaxSetupCount = 0;
5273 pSMB->Reserved = 0;
5274 pSMB->Flags = 0;
5275 pSMB->Timeout = 0;
5276 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005277 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5278 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005279 offset = param_offset + params;
5280
5281 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005282 /* BB find exact max SMB PDU from sess structure BB */
5283 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005284 pSMB->SetupCount = 1;
5285 pSMB->Reserved3 = 0;
5286 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5287 byte_count = 1 /* pad */ + params + 12;
5288
5289 pSMB->DataCount = cpu_to_le16(12);
5290 pSMB->ParameterCount = cpu_to_le16(params);
5291 pSMB->TotalDataCount = pSMB->DataCount;
5292 pSMB->TotalParameterCount = pSMB->ParameterCount;
5293 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5294 pSMB->DataOffset = cpu_to_le16(offset);
5295
5296 /* Params. */
5297 pSMB->FileNum = 0;
5298 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5299
5300 /* Data. */
5301 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5302 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5303 pSMB->ClientUnixCap = cpu_to_le64(cap);
5304
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005305 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005306 pSMB->ByteCount = cpu_to_le16(byte_count);
5307
5308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5310 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005311 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005312 } else { /* decode response */
5313 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005314 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005315 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005316 }
5317 cifs_buf_release(pSMB);
5318
5319 if (rc == -EAGAIN)
5320 goto SETFSUnixRetry;
5321
5322 return rc;
5323}
5324
5325
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326
5327int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005328CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005329 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330{
5331/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5332 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5333 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5334 FILE_SYSTEM_POSIX_INFO *response_data;
5335 int rc = 0;
5336 int bytes_returned = 0;
5337 __u16 params, byte_count;
5338
Joe Perchesf96637b2013-05-04 22:12:25 -05005339 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340QFSPosixRetry:
5341 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5342 (void **) &pSMBr);
5343 if (rc)
5344 return rc;
5345
5346 params = 2; /* level */
5347 pSMB->TotalDataCount = 0;
5348 pSMB->DataCount = 0;
5349 pSMB->DataOffset = 0;
5350 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005351 /* BB find exact max SMB PDU from sess structure BB */
5352 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 pSMB->MaxSetupCount = 0;
5354 pSMB->Reserved = 0;
5355 pSMB->Flags = 0;
5356 pSMB->Timeout = 0;
5357 pSMB->Reserved2 = 0;
5358 byte_count = params + 1 /* pad */ ;
5359 pSMB->ParameterCount = cpu_to_le16(params);
5360 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005361 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5362 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 pSMB->SetupCount = 1;
5364 pSMB->Reserved3 = 0;
5365 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5366 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005367 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 pSMB->ByteCount = cpu_to_le16(byte_count);
5369
5370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5372 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005373 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 } else { /* decode response */
5375 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5376
Jeff Layton820a8032011-05-04 08:05:26 -04005377 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 rc = -EIO; /* bad smb */
5379 } else {
5380 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5381 response_data =
5382 (FILE_SYSTEM_POSIX_INFO
5383 *) (((char *) &pSMBr->hdr.Protocol) +
5384 data_offset);
5385 FSData->f_bsize =
5386 le32_to_cpu(response_data->BlockSize);
5387 FSData->f_blocks =
5388 le64_to_cpu(response_data->TotalBlocks);
5389 FSData->f_bfree =
5390 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005391 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 FSData->f_bavail = FSData->f_bfree;
5393 } else {
5394 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005395 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 }
Steve French790fe572007-07-07 19:25:05 +00005397 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005399 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005400 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005402 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 }
5404 }
5405 cifs_buf_release(pSMB);
5406
5407 if (rc == -EAGAIN)
5408 goto QFSPosixRetry;
5409
5410 return rc;
5411}
5412
5413
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005414/*
5415 * We can not use write of zero bytes trick to set file size due to need for
5416 * large file support. Also note that this SetPathInfo is preferred to
5417 * SetFileInfo based method in next routine which is only needed to work around
5418 * a sharing violation bugin Samba which this routine can run into.
5419 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005421CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005422 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5423 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424{
5425 struct smb_com_transaction2_spi_req *pSMB = NULL;
5426 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5427 struct file_end_of_file_info *parm_data;
5428 int name_len;
5429 int rc = 0;
5430 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005431 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5432
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 __u16 params, byte_count, data_count, param_offset, offset;
5434
Joe Perchesf96637b2013-05-04 22:12:25 -05005435 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436SetEOFRetry:
5437 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5438 (void **) &pSMBr);
5439 if (rc)
5440 return rc;
5441
5442 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5443 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005444 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5445 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 name_len++; /* trailing null */
5447 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005448 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005449 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005451 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 }
5453 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005454 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005456 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 pSMB->MaxSetupCount = 0;
5458 pSMB->Reserved = 0;
5459 pSMB->Flags = 0;
5460 pSMB->Timeout = 0;
5461 pSMB->Reserved2 = 0;
5462 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005463 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005465 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005466 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5467 pSMB->InformationLevel =
5468 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5469 else
5470 pSMB->InformationLevel =
5471 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5472 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5474 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005475 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 else
5477 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005478 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 }
5480
5481 parm_data =
5482 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5483 offset);
5484 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5485 pSMB->DataOffset = cpu_to_le16(offset);
5486 pSMB->SetupCount = 1;
5487 pSMB->Reserved3 = 0;
5488 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5489 byte_count = 3 /* pad */ + params + data_count;
5490 pSMB->DataCount = cpu_to_le16(data_count);
5491 pSMB->TotalDataCount = pSMB->DataCount;
5492 pSMB->ParameterCount = cpu_to_le16(params);
5493 pSMB->TotalParameterCount = pSMB->ParameterCount;
5494 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005495 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 parm_data->FileSize = cpu_to_le64(size);
5497 pSMB->ByteCount = cpu_to_le16(byte_count);
5498 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005500 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005501 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502
5503 cifs_buf_release(pSMB);
5504
5505 if (rc == -EAGAIN)
5506 goto SetEOFRetry;
5507
5508 return rc;
5509}
5510
5511int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005512CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5513 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514{
5515 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 struct file_end_of_file_info *parm_data;
5517 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 __u16 params, param_offset, offset, byte_count, count;
5519
Joe Perchesf96637b2013-05-04 22:12:25 -05005520 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5521 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005522 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5523
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 if (rc)
5525 return rc;
5526
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005527 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5528 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005529
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 params = 6;
5531 pSMB->MaxSetupCount = 0;
5532 pSMB->Reserved = 0;
5533 pSMB->Flags = 0;
5534 pSMB->Timeout = 0;
5535 pSMB->Reserved2 = 0;
5536 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5537 offset = param_offset + params;
5538
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 count = sizeof(struct file_end_of_file_info);
5540 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005541 /* BB find exact max SMB PDU from sess structure BB */
5542 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 pSMB->SetupCount = 1;
5544 pSMB->Reserved3 = 0;
5545 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5546 byte_count = 3 /* pad */ + params + count;
5547 pSMB->DataCount = cpu_to_le16(count);
5548 pSMB->ParameterCount = cpu_to_le16(params);
5549 pSMB->TotalDataCount = pSMB->DataCount;
5550 pSMB->TotalParameterCount = pSMB->ParameterCount;
5551 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5552 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005553 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5554 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 pSMB->DataOffset = cpu_to_le16(offset);
5556 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005557 pSMB->Fid = cfile->fid.netfid;
5558 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5560 pSMB->InformationLevel =
5561 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5562 else
5563 pSMB->InformationLevel =
5564 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005565 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5567 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005568 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 else
5570 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005571 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 }
5573 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005574 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005576 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005578 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5579 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 }
5581
Steve French50c2f752007-07-13 00:33:32 +00005582 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 since file handle passed in no longer valid */
5584
5585 return rc;
5586}
5587
Steve French50c2f752007-07-13 00:33:32 +00005588/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 an open handle, rather than by pathname - this is awkward due to
5590 potential access conflicts on the open, but it is unavoidable for these
5591 old servers since the only other choice is to go from 100 nanosecond DCE
5592 time and resort to the original setpathinfo level which takes the ancient
5593 DOS time format with 2 second granularity */
5594int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005595CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005596 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597{
5598 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 char *data_offset;
5600 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 __u16 params, param_offset, offset, byte_count, count;
5602
Joe Perchesf96637b2013-05-04 22:12:25 -05005603 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005604 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5605
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 if (rc)
5607 return rc;
5608
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005609 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5610 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005611
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 params = 6;
5613 pSMB->MaxSetupCount = 0;
5614 pSMB->Reserved = 0;
5615 pSMB->Flags = 0;
5616 pSMB->Timeout = 0;
5617 pSMB->Reserved2 = 0;
5618 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5619 offset = param_offset + params;
5620
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005621 data_offset = (char *)pSMB +
5622 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623
Steve French26f57362007-08-30 22:09:15 +00005624 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005626 /* BB find max SMB PDU from sess */
5627 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 pSMB->SetupCount = 1;
5629 pSMB->Reserved3 = 0;
5630 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5631 byte_count = 3 /* pad */ + params + count;
5632 pSMB->DataCount = cpu_to_le16(count);
5633 pSMB->ParameterCount = cpu_to_le16(params);
5634 pSMB->TotalDataCount = pSMB->DataCount;
5635 pSMB->TotalParameterCount = pSMB->ParameterCount;
5636 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5637 pSMB->DataOffset = cpu_to_le16(offset);
5638 pSMB->Fid = fid;
5639 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5640 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5641 else
5642 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5643 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005644 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005646 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005647 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005648 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005649 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5650 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651
Steve French50c2f752007-07-13 00:33:32 +00005652 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 since file handle passed in no longer valid */
5654
5655 return rc;
5656}
5657
Jeff Layton6d22f092008-09-23 11:48:35 -04005658int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005659CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005660 bool delete_file, __u16 fid, __u32 pid_of_opener)
5661{
5662 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5663 char *data_offset;
5664 int rc = 0;
5665 __u16 params, param_offset, offset, byte_count, count;
5666
Joe Perchesf96637b2013-05-04 22:12:25 -05005667 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005668 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5669
5670 if (rc)
5671 return rc;
5672
5673 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5674 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5675
5676 params = 6;
5677 pSMB->MaxSetupCount = 0;
5678 pSMB->Reserved = 0;
5679 pSMB->Flags = 0;
5680 pSMB->Timeout = 0;
5681 pSMB->Reserved2 = 0;
5682 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5683 offset = param_offset + params;
5684
5685 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5686
5687 count = 1;
5688 pSMB->MaxParameterCount = cpu_to_le16(2);
5689 /* BB find max SMB PDU from sess */
5690 pSMB->MaxDataCount = cpu_to_le16(1000);
5691 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 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5703 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005704 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005705 pSMB->ByteCount = cpu_to_le16(byte_count);
5706 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005707 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005708 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005709 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005710
5711 return rc;
5712}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713
5714int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005715CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005716 const char *fileName, const FILE_BASIC_INFO *data,
5717 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718{
5719 TRANSACTION2_SPI_REQ *pSMB = NULL;
5720 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5721 int name_len;
5722 int rc = 0;
5723 int bytes_returned = 0;
5724 char *data_offset;
5725 __u16 params, param_offset, offset, byte_count, count;
5726
Joe Perchesf96637b2013-05-04 22:12:25 -05005727 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728
5729SetTimesRetry:
5730 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5731 (void **) &pSMBr);
5732 if (rc)
5733 return rc;
5734
5735 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5736 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005737 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5738 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 name_len++; /* trailing null */
5740 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005741 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 name_len = strnlen(fileName, PATH_MAX);
5743 name_len++; /* trailing null */
5744 strncpy(pSMB->FileName, fileName, name_len);
5745 }
5746
5747 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005748 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005750 /* BB find max SMB PDU from sess structure BB */
5751 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752 pSMB->MaxSetupCount = 0;
5753 pSMB->Reserved = 0;
5754 pSMB->Flags = 0;
5755 pSMB->Timeout = 0;
5756 pSMB->Reserved2 = 0;
5757 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005758 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 offset = param_offset + params;
5760 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5761 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5762 pSMB->DataOffset = cpu_to_le16(offset);
5763 pSMB->SetupCount = 1;
5764 pSMB->Reserved3 = 0;
5765 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5766 byte_count = 3 /* pad */ + params + count;
5767
5768 pSMB->DataCount = cpu_to_le16(count);
5769 pSMB->ParameterCount = cpu_to_le16(params);
5770 pSMB->TotalDataCount = pSMB->DataCount;
5771 pSMB->TotalParameterCount = pSMB->ParameterCount;
5772 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5773 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5774 else
5775 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5776 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005777 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005778 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 pSMB->ByteCount = cpu_to_le16(byte_count);
5780 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5781 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005782 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005783 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
5785 cifs_buf_release(pSMB);
5786
5787 if (rc == -EAGAIN)
5788 goto SetTimesRetry;
5789
5790 return rc;
5791}
5792
5793/* Can not be used to set time stamps yet (due to old DOS time format) */
5794/* Can be used to set attributes */
5795#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5796 handling it anyway and NT4 was what we thought it would be needed for
5797 Do not delete it until we prove whether needed for Win9x though */
5798int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005799CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 __u16 dos_attrs, const struct nls_table *nls_codepage)
5801{
5802 SETATTR_REQ *pSMB = NULL;
5803 SETATTR_RSP *pSMBr = NULL;
5804 int rc = 0;
5805 int bytes_returned;
5806 int name_len;
5807
Joe Perchesf96637b2013-05-04 22:12:25 -05005808 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809
5810SetAttrLgcyRetry:
5811 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5812 (void **) &pSMBr);
5813 if (rc)
5814 return rc;
5815
5816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5817 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005818 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5819 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 name_len++; /* trailing null */
5821 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005822 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 name_len = strnlen(fileName, PATH_MAX);
5824 name_len++; /* trailing null */
5825 strncpy(pSMB->fileName, fileName, name_len);
5826 }
5827 pSMB->attr = cpu_to_le16(dos_attrs);
5828 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005829 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005833 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005834 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835
5836 cifs_buf_release(pSMB);
5837
5838 if (rc == -EAGAIN)
5839 goto SetAttrLgcyRetry;
5840
5841 return rc;
5842}
5843#endif /* temporarily unneeded SetAttr legacy function */
5844
Jeff Layton654cf142009-07-09 20:02:49 -04005845static void
5846cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5847 const struct cifs_unix_set_info_args *args)
5848{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005849 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005850 u64 mode = args->mode;
5851
Eric W. Biederman49418b22013-02-06 00:57:56 -08005852 if (uid_valid(args->uid))
5853 uid = from_kuid(&init_user_ns, args->uid);
5854 if (gid_valid(args->gid))
5855 gid = from_kgid(&init_user_ns, args->gid);
5856
Jeff Layton654cf142009-07-09 20:02:49 -04005857 /*
5858 * Samba server ignores set of file size to zero due to bugs in some
5859 * older clients, but we should be precise - we use SetFileSize to
5860 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005861 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005862 * zero instead of -1 here
5863 */
5864 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5865 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5866 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5867 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5868 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005869 data_offset->Uid = cpu_to_le64(uid);
5870 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005871 /* better to leave device as zero when it is */
5872 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5873 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5874 data_offset->Permissions = cpu_to_le64(mode);
5875
5876 if (S_ISREG(mode))
5877 data_offset->Type = cpu_to_le32(UNIX_FILE);
5878 else if (S_ISDIR(mode))
5879 data_offset->Type = cpu_to_le32(UNIX_DIR);
5880 else if (S_ISLNK(mode))
5881 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5882 else if (S_ISCHR(mode))
5883 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5884 else if (S_ISBLK(mode))
5885 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5886 else if (S_ISFIFO(mode))
5887 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5888 else if (S_ISSOCK(mode))
5889 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5890}
5891
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005893CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005894 const struct cifs_unix_set_info_args *args,
5895 u16 fid, u32 pid_of_opener)
5896{
5897 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005898 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005899 int rc = 0;
5900 u16 params, param_offset, offset, byte_count, count;
5901
Joe Perchesf96637b2013-05-04 22:12:25 -05005902 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005903 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5904
5905 if (rc)
5906 return rc;
5907
5908 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5909 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5910
5911 params = 6;
5912 pSMB->MaxSetupCount = 0;
5913 pSMB->Reserved = 0;
5914 pSMB->Flags = 0;
5915 pSMB->Timeout = 0;
5916 pSMB->Reserved2 = 0;
5917 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5918 offset = param_offset + params;
5919
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005920 data_offset = (char *)pSMB +
5921 offsetof(struct smb_hdr, Protocol) + offset;
5922
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005923 count = sizeof(FILE_UNIX_BASIC_INFO);
5924
5925 pSMB->MaxParameterCount = cpu_to_le16(2);
5926 /* BB find max SMB PDU from sess */
5927 pSMB->MaxDataCount = cpu_to_le16(1000);
5928 pSMB->SetupCount = 1;
5929 pSMB->Reserved3 = 0;
5930 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5931 byte_count = 3 /* pad */ + params + count;
5932 pSMB->DataCount = cpu_to_le16(count);
5933 pSMB->ParameterCount = cpu_to_le16(params);
5934 pSMB->TotalDataCount = pSMB->DataCount;
5935 pSMB->TotalParameterCount = pSMB->ParameterCount;
5936 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5937 pSMB->DataOffset = cpu_to_le16(offset);
5938 pSMB->Fid = fid;
5939 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5940 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005941 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005942 pSMB->ByteCount = cpu_to_le16(byte_count);
5943
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005944 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005945
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005946 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005947 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005948 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5949 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005950
5951 /* Note: On -EAGAIN error only caller can retry on handle based calls
5952 since file handle passed in no longer valid */
5953
5954 return rc;
5955}
5956
5957int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005958CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005959 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005960 const struct cifs_unix_set_info_args *args,
5961 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962{
5963 TRANSACTION2_SPI_REQ *pSMB = NULL;
5964 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5965 int name_len;
5966 int rc = 0;
5967 int bytes_returned = 0;
5968 FILE_UNIX_BASIC_INFO *data_offset;
5969 __u16 params, param_offset, offset, count, byte_count;
5970
Joe Perchesf96637b2013-05-04 22:12:25 -05005971 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972setPermsRetry:
5973 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5974 (void **) &pSMBr);
5975 if (rc)
5976 return rc;
5977
5978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5979 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005980 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005981 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 name_len++; /* trailing null */
5983 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005984 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005985 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005987 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 }
5989
5990 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005991 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005993 /* BB find max SMB PDU from sess structure BB */
5994 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 pSMB->MaxSetupCount = 0;
5996 pSMB->Reserved = 0;
5997 pSMB->Flags = 0;
5998 pSMB->Timeout = 0;
5999 pSMB->Reserved2 = 0;
6000 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006001 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002 offset = param_offset + params;
6003 data_offset =
6004 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6005 offset);
6006 memset(data_offset, 0, count);
6007 pSMB->DataOffset = cpu_to_le16(offset);
6008 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6009 pSMB->SetupCount = 1;
6010 pSMB->Reserved3 = 0;
6011 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6012 byte_count = 3 /* pad */ + params + count;
6013 pSMB->ParameterCount = cpu_to_le16(params);
6014 pSMB->DataCount = cpu_to_le16(count);
6015 pSMB->TotalParameterCount = pSMB->ParameterCount;
6016 pSMB->TotalDataCount = pSMB->DataCount;
6017 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6018 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006019 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006020
Jeff Layton654cf142009-07-09 20:02:49 -04006021 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022
6023 pSMB->ByteCount = cpu_to_le16(byte_count);
6024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006026 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006027 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028
Steve French0d817bc2008-05-22 02:02:03 +00006029 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030 if (rc == -EAGAIN)
6031 goto setPermsRetry;
6032 return rc;
6033}
6034
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006036/*
6037 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6038 * function used by listxattr and getxattr type calls. When ea_name is set,
6039 * it looks for that attribute name and stuffs that value into the EAData
6040 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6041 * buffer. In both cases, the return value is either the length of the
6042 * resulting data or a negative error code. If EAData is a NULL pointer then
6043 * the data isn't copied to it, but the length is returned.
6044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006046CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006047 const unsigned char *searchName, const unsigned char *ea_name,
6048 char *EAData, size_t buf_size,
6049 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050{
6051 /* BB assumes one setup word */
6052 TRANSACTION2_QPI_REQ *pSMB = NULL;
6053 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6054 int rc = 0;
6055 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006056 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006057 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006058 struct fea *temp_fea;
6059 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006060 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006061 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006062 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063
Joe Perchesf96637b2013-05-04 22:12:25 -05006064 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065QAllEAsRetry:
6066 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6067 (void **) &pSMBr);
6068 if (rc)
6069 return rc;
6070
6071 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006072 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006073 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6074 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006075 list_len++; /* trailing null */
6076 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006078 list_len = strnlen(searchName, PATH_MAX);
6079 list_len++; /* trailing null */
6080 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081 }
6082
Jeff Layton6e462b92010-02-10 16:18:26 -05006083 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084 pSMB->TotalDataCount = 0;
6085 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006086 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006087 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 pSMB->MaxSetupCount = 0;
6089 pSMB->Reserved = 0;
6090 pSMB->Flags = 0;
6091 pSMB->Timeout = 0;
6092 pSMB->Reserved2 = 0;
6093 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006094 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 pSMB->DataCount = 0;
6096 pSMB->DataOffset = 0;
6097 pSMB->SetupCount = 1;
6098 pSMB->Reserved3 = 0;
6099 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6100 byte_count = params + 1 /* pad */ ;
6101 pSMB->TotalParameterCount = cpu_to_le16(params);
6102 pSMB->ParameterCount = pSMB->TotalParameterCount;
6103 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6104 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006105 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 pSMB->ByteCount = cpu_to_le16(byte_count);
6107
6108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6109 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6110 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006111 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006112 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006114
6115
6116 /* BB also check enough total bytes returned */
6117 /* BB we need to improve the validity checking
6118 of these trans2 responses */
6119
6120 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006121 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006122 rc = -EIO; /* bad smb */
6123 goto QAllEAsOut;
6124 }
6125
6126 /* check that length of list is not more than bcc */
6127 /* check that each entry does not go beyond length
6128 of list */
6129 /* check that each element of each entry does not
6130 go beyond end of list */
6131 /* validate_trans2_offsets() */
6132 /* BB check if start of smb + data_offset > &bcc+ bcc */
6133
6134 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6135 ea_response_data = (struct fealist *)
6136 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6137
Jeff Layton6e462b92010-02-10 16:18:26 -05006138 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006139 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006140 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006141 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006142 goto QAllEAsOut;
6143 }
6144
Jeff Layton0cd126b2010-02-10 16:18:26 -05006145 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006146 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006147 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006148 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006149 rc = -EIO;
6150 goto QAllEAsOut;
6151 }
6152
Jeff Laytonf0d38682010-02-10 16:18:26 -05006153 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006154 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006155 temp_fea = ea_response_data->list;
6156 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006157 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006158 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006159 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006160
Jeff Layton6e462b92010-02-10 16:18:26 -05006161 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006162 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006163 /* make sure we can read name_len and value_len */
6164 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006165 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006166 rc = -EIO;
6167 goto QAllEAsOut;
6168 }
6169
6170 name_len = temp_fea->name_len;
6171 value_len = le16_to_cpu(temp_fea->value_len);
6172 list_len -= name_len + 1 + value_len;
6173 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006174 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006175 rc = -EIO;
6176 goto QAllEAsOut;
6177 }
6178
Jeff Layton31c05192010-02-10 16:18:26 -05006179 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006180 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006181 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006182 temp_ptr += name_len + 1;
6183 rc = value_len;
6184 if (buf_size == 0)
6185 goto QAllEAsOut;
6186 if ((size_t)value_len > buf_size) {
6187 rc = -ERANGE;
6188 goto QAllEAsOut;
6189 }
6190 memcpy(EAData, temp_ptr, value_len);
6191 goto QAllEAsOut;
6192 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006193 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006194 /* account for prefix user. and trailing null */
6195 rc += (5 + 1 + name_len);
6196 if (rc < (int) buf_size) {
6197 memcpy(EAData, "user.", 5);
6198 EAData += 5;
6199 memcpy(EAData, temp_ptr, name_len);
6200 EAData += name_len;
6201 /* null terminate name */
6202 *EAData = 0;
6203 ++EAData;
6204 } else if (buf_size == 0) {
6205 /* skip copy - calc size only */
6206 } else {
6207 /* stop before overrun buffer */
6208 rc = -ERANGE;
6209 break;
6210 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006211 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006212 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006213 temp_fea = (struct fea *)temp_ptr;
6214 }
6215
Jeff Layton31c05192010-02-10 16:18:26 -05006216 /* didn't find the named attribute */
6217 if (ea_name)
6218 rc = -ENODATA;
6219
Jeff Laytonf0d38682010-02-10 16:18:26 -05006220QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006221 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 if (rc == -EAGAIN)
6223 goto QAllEAsRetry;
6224
6225 return (ssize_t)rc;
6226}
6227
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006229CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6230 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006231 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6232 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233{
6234 struct smb_com_transaction2_spi_req *pSMB = NULL;
6235 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6236 struct fealist *parm_data;
6237 int name_len;
6238 int rc = 0;
6239 int bytes_returned = 0;
6240 __u16 params, param_offset, byte_count, offset, count;
6241
Joe Perchesf96637b2013-05-04 22:12:25 -05006242 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243SetEARetry:
6244 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6245 (void **) &pSMBr);
6246 if (rc)
6247 return rc;
6248
6249 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6250 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006251 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6252 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 name_len++; /* trailing null */
6254 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006255 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 name_len = strnlen(fileName, PATH_MAX);
6257 name_len++; /* trailing null */
6258 strncpy(pSMB->FileName, fileName, name_len);
6259 }
6260
6261 params = 6 + name_len;
6262
6263 /* done calculating parms using name_len of file name,
6264 now use name_len to calculate length of ea name
6265 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006266 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267 name_len = 0;
6268 else
Steve French50c2f752007-07-13 00:33:32 +00006269 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006271 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006273 /* BB find max SMB PDU from sess */
6274 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275 pSMB->MaxSetupCount = 0;
6276 pSMB->Reserved = 0;
6277 pSMB->Flags = 0;
6278 pSMB->Timeout = 0;
6279 pSMB->Reserved2 = 0;
6280 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006281 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 offset = param_offset + params;
6283 pSMB->InformationLevel =
6284 cpu_to_le16(SMB_SET_FILE_EA);
6285
6286 parm_data =
6287 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6288 offset);
6289 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6290 pSMB->DataOffset = cpu_to_le16(offset);
6291 pSMB->SetupCount = 1;
6292 pSMB->Reserved3 = 0;
6293 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6294 byte_count = 3 /* pad */ + params + count;
6295 pSMB->DataCount = cpu_to_le16(count);
6296 parm_data->list_len = cpu_to_le32(count);
6297 parm_data->list[0].EA_flags = 0;
6298 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006299 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006301 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006302 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303 parm_data->list[0].name[name_len] = 0;
6304 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6305 /* caller ensures that ea_value_len is less than 64K but
6306 we need to ensure that it fits within the smb */
6307
Steve French50c2f752007-07-13 00:33:32 +00006308 /*BB add length check to see if it would fit in
6309 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006310 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6311 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006312 memcpy(parm_data->list[0].name+name_len+1,
6313 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
6315 pSMB->TotalDataCount = pSMB->DataCount;
6316 pSMB->ParameterCount = cpu_to_le16(params);
6317 pSMB->TotalParameterCount = pSMB->ParameterCount;
6318 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006319 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 pSMB->ByteCount = cpu_to_le16(byte_count);
6321 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6322 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006323 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006324 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325
6326 cifs_buf_release(pSMB);
6327
6328 if (rc == -EAGAIN)
6329 goto SetEARetry;
6330
6331 return rc;
6332}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333#endif
Steve French0eff0e22011-02-24 05:39:23 +00006334
6335#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6336/*
6337 * Years ago the kernel added a "dnotify" function for Samba server,
6338 * to allow network clients (such as Windows) to display updated
6339 * lists of files in directory listings automatically when
6340 * files are added by one user when another user has the
6341 * same directory open on their desktop. The Linux cifs kernel
6342 * client hooked into the kernel side of this interface for
6343 * the same reason, but ironically when the VFS moved from
6344 * "dnotify" to "inotify" it became harder to plug in Linux
6345 * network file system clients (the most obvious use case
6346 * for notify interfaces is when multiple users can update
6347 * the contents of the same directory - exactly what network
6348 * file systems can do) although the server (Samba) could
6349 * still use it. For the short term we leave the worker
6350 * function ifdeffed out (below) until inotify is fixed
6351 * in the VFS to make it easier to plug in network file
6352 * system clients. If inotify turns out to be permanently
6353 * incompatible for network fs clients, we could instead simply
6354 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6355 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006356int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006357 const int notify_subdirs, const __u16 netfid,
6358 __u32 filter, struct file *pfile, int multishot,
6359 const struct nls_table *nls_codepage)
6360{
6361 int rc = 0;
6362 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6363 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6364 struct dir_notify_req *dnotify_req;
6365 int bytes_returned;
6366
Joe Perchesf96637b2013-05-04 22:12:25 -05006367 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006368 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6369 (void **) &pSMBr);
6370 if (rc)
6371 return rc;
6372
6373 pSMB->TotalParameterCount = 0 ;
6374 pSMB->TotalDataCount = 0;
6375 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006376 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006377 pSMB->MaxSetupCount = 4;
6378 pSMB->Reserved = 0;
6379 pSMB->ParameterOffset = 0;
6380 pSMB->DataCount = 0;
6381 pSMB->DataOffset = 0;
6382 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6383 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6384 pSMB->ParameterCount = pSMB->TotalParameterCount;
6385 if (notify_subdirs)
6386 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6387 pSMB->Reserved2 = 0;
6388 pSMB->CompletionFilter = cpu_to_le32(filter);
6389 pSMB->Fid = netfid; /* file handle always le */
6390 pSMB->ByteCount = 0;
6391
6392 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6393 (struct smb_hdr *)pSMBr, &bytes_returned,
6394 CIFS_ASYNC_OP);
6395 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006396 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006397 } else {
6398 /* Add file to outstanding requests */
6399 /* BB change to kmem cache alloc */
6400 dnotify_req = kmalloc(
6401 sizeof(struct dir_notify_req),
6402 GFP_KERNEL);
6403 if (dnotify_req) {
6404 dnotify_req->Pid = pSMB->hdr.Pid;
6405 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6406 dnotify_req->Mid = pSMB->hdr.Mid;
6407 dnotify_req->Tid = pSMB->hdr.Tid;
6408 dnotify_req->Uid = pSMB->hdr.Uid;
6409 dnotify_req->netfid = netfid;
6410 dnotify_req->pfile = pfile;
6411 dnotify_req->filter = filter;
6412 dnotify_req->multishot = multishot;
6413 spin_lock(&GlobalMid_Lock);
6414 list_add_tail(&dnotify_req->lhead,
6415 &GlobalDnotifyReqList);
6416 spin_unlock(&GlobalMid_Lock);
6417 } else
6418 rc = -ENOMEM;
6419 }
6420 cifs_buf_release(pSMB);
6421 return rc;
6422}
6423#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */