blob: a58dc77cc4430d57d8c8226c3120f3a12519fb00 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400371CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 NEGOTIATE_REQ *pSMB;
374 NEGOTIATE_RSP *pSMBr;
375 int rc = 0;
376 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000377 int i;
Steve French50c2f752007-07-13 00:33:32 +0000378 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000380 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Steve French790fe572007-07-07 19:25:05 +0000382 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 server = ses->server;
384 else {
385 rc = -EIO;
386 return rc;
387 }
388 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
389 (void **) &pSMB, (void **) &pSMBr);
390 if (rc)
391 return rc;
Steve French750d1152006-06-27 06:28:30 +0000392
393 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000394 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000395 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000396 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400397 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000398
Joe Perchesf96637b2013-05-04 22:12:25 -0500399 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000400
Pavel Shilovsky88257362012-05-23 14:01:59 +0400401 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000402 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000403
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000404 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000405 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000406 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500407 cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
Steve Frencha0136892007-10-04 20:05:09 +0000408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500409 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500412 cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
414 }
Steve French50c2f752007-07-13 00:33:32 +0000415
Steve French39798772006-05-31 22:40:51 +0000416 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000417 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000418 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
419 count += strlen(protocols[i].name) + 1;
420 /* null at end of source and target buffers anyway */
421 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000422 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->ByteCount = cpu_to_le16(count);
424
425 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000427 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000428 goto neg_err_exit;
429
Jeff Layton9bf67e52010-04-24 07:57:46 -0400430 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500431 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000432 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400433 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000434 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000435 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000436 could not negotiate a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000439#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000440 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400441 && ((server->dialect == LANMAN_PROT)
442 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000443 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000444 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000445
Steve French790fe572007-07-07 19:25:05 +0000446 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000447 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000448 server->secType = LANMAN;
449 else {
Joe Perchesf96637b2013-05-04 22:12:25 -0500450 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
Steve French39798772006-05-31 22:40:51 +0000451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000453 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400454 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300455 server->maxReq = min_t(unsigned int,
456 le16_to_cpu(rsp->MaxMpxCount),
457 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400458 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400459 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000460 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000461 /* even though we do not use raw we might as well set this
462 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000463 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000464 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000465 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
466 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000467 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000468 server->capabilities = CAP_MPX_MODE;
469 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000470 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000471 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000472 /* OS/2 often does not set timezone therefore
473 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000474 * Could deviate slightly from the right zone.
475 * Smallest defined timezone difference is 15 minutes
476 * (i.e. Nepal). Rounding up/down is done to match
477 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000478 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000479 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000480 struct timespec ts, utc;
481 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400482 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
483 rsp->SrvTime.Time, 0);
Joe Perchesf96637b2013-05-04 22:12:25 -0500484 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
485 (int)ts.tv_sec, (int)utc.tv_sec,
486 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000487 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000488 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000489 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000490 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000491 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000492 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000493 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000494 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000495 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000496 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000497 server->timeAdj = (int)tmp;
498 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000499 }
Joe Perchesf96637b2013-05-04 22:12:25 -0500500 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000501
Steve French39798772006-05-31 22:40:51 +0000502
Steve French254e55e2006-06-04 05:53:15 +0000503 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000504 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000505
Steve French50c2f752007-07-13 00:33:32 +0000506 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000507 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500508 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000509 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000510 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000511 rc = -EIO; /* need cryptkey unless plain text */
512 goto neg_err_exit;
513 }
Steve French39798772006-05-31 22:40:51 +0000514
Joe Perchesf96637b2013-05-04 22:12:25 -0500515 cifs_dbg(FYI, "LANMAN negotiated\n");
Steve French254e55e2006-06-04 05:53:15 +0000516 /* we will not end up setting signing flags - as no signing
517 was in LANMAN and server did not return the flags on */
518 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000519#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000520 } else if (pSMBr->hdr.WordCount == 13) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500521 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300522 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000523#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000524 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000525 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000526 /* unknown wct */
527 rc = -EOPNOTSUPP;
528 goto neg_err_exit;
529 }
530 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000531 server->sec_mode = pSMBr->SecurityMode;
532 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500533 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000534
Steve French96daf2b2011-05-27 04:34:02 +0000535 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000536#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000537 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000538#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500539 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000540
Steve French790fe572007-07-07 19:25:05 +0000541 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000542 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000543 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000544 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000545 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000546 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000547 else if (secFlags & CIFSSEC_MAY_KRB5)
548 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000549 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000550 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000551 else if (secFlags & CIFSSEC_MAY_LANMAN)
552 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000553 else {
554 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500555 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000556 goto neg_err_exit;
557 }
558 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000559
Steve French254e55e2006-06-04 05:53:15 +0000560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300562 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
563 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400564 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000565 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400566 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000567 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500568 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000569 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000570 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
571 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000572 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500573 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000574 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000575 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
576 server->capabilities & CAP_EXTENDED_SECURITY) &&
577 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000578 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400579 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000580 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000582 goto neg_err_exit;
583 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530584 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500585 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530586 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000587 if (memcmp(server->server_GUID,
588 pSMBr->u.extended_response.
589 GUID, 16) != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500590 cifs_dbg(FYI, "server UID changed\n");
Steve French254e55e2006-06-04 05:53:15 +0000591 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000592 pSMBr->u.extended_response.GUID,
593 16);
594 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500595 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530596 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000597 memcpy(server->server_GUID,
598 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500599 }
Jeff Laytone187e442007-10-16 17:10:44 +0000600
601 if (count == 16) {
602 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000603 } else {
604 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400605 SecurityBlob, count - 16,
606 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000607 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000608 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000609 else
Steve French254e55e2006-06-04 05:53:15 +0000610 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500611 if (server->secType == Kerberos) {
612 if (!server->sec_kerberos &&
613 !server->sec_mskerberos)
614 rc = -EOPNOTSUPP;
615 } else if (server->secType == RawNTLMSSP) {
616 if (!server->sec_ntlmssp)
617 rc = -EOPNOTSUPP;
618 } else
619 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 }
Steve French96daf2b2011-05-27 04:34:02 +0000621 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000622 rc = -EIO; /* no crypt key only if plain text pwd */
623 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000624 } else
625 server->capabilities &= ~CAP_EXTENDED_SECURITY;
626
Steve French6344a422006-06-12 04:18:35 +0000627#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000628signing_check:
Steve French6344a422006-06-12 04:18:35 +0000629#endif
Steve French762e5ab2007-06-28 18:41:42 +0000630 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
631 /* MUST_SIGN already includes the MAY_SIGN FLAG
632 so if this is zero it means that signing is disabled */
Joe Perchesf96637b2013-05-04 22:12:25 -0500633 cifs_dbg(FYI, "Signing disabled\n");
Steve French96daf2b2011-05-27 04:34:02 +0000634 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500635 cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
Steve Frenchabb63d62007-10-18 02:58:40 +0000636 rc = -EOPNOTSUPP;
637 }
Steve French96daf2b2011-05-27 04:34:02 +0000638 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000639 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000640 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
641 /* signing required */
Joe Perchesf96637b2013-05-04 22:12:25 -0500642 cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000643 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000644 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500645 cifs_dbg(VFS, "signing required but server lacks support\n");
Jeff38c10a12007-07-06 21:10:07 +0000646 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000647 } else
Steve French96daf2b2011-05-27 04:34:02 +0000648 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000649 } else {
650 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000651 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
652 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000653 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Steve French50c2f752007-07-13 00:33:32 +0000655
656neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700657 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000658
Joe Perchesf96637b2013-05-04 22:12:25 -0500659 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 return rc;
661}
662
663int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400664CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
666 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Joe Perchesf96637b2013-05-04 22:12:25 -0500669 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500670
671 /* BB: do we need to check this? These should never be NULL. */
672 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
673 return -EIO;
674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500676 * No need to return error on this operation if tid invalidated and
677 * closed on server already e.g. due to tcp session crashing. Also,
678 * the tcon is no longer on the list, so no need to take lock before
679 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 */
Steve French268875b2009-06-25 00:29:21 +0000681 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000682 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Steve French50c2f752007-07-13 00:33:32 +0000684 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700685 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500686 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return rc;
Steve French133672e2007-11-13 22:41:37 +0000688
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400689 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500691 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Steve French50c2f752007-07-13 00:33:32 +0000693 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500694 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc == -EAGAIN)
696 rc = 0;
697
698 return rc;
699}
700
Jeff Layton766fdbb2011-01-11 07:24:21 -0500701/*
702 * This is a no-op for now. We're not really interested in the reply, but
703 * rather in the fact that the server sent one and that server->lstrp
704 * gets updated.
705 *
706 * FIXME: maybe we should consider checking that the reply matches request?
707 */
708static void
709cifs_echo_callback(struct mid_q_entry *mid)
710{
711 struct TCP_Server_Info *server = mid->callback_data;
712
713 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400714 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500715}
716
717int
718CIFSSMBEcho(struct TCP_Server_Info *server)
719{
720 ECHO_REQ *smb;
721 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400722 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700723 struct smb_rqst rqst = { .rq_iov = &iov,
724 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725
Joe Perchesf96637b2013-05-04 22:12:25 -0500726 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500727
728 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
729 if (rc)
730 return rc;
731
732 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000733 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500734 smb->hdr.WordCount = 1;
735 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400736 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000738 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400739 iov.iov_base = smb;
740 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741
Jeff Laytonfec344e2012-09-18 16:20:35 -0700742 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400743 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500744 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500745 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
747 cifs_small_buf_release(smb);
748
749 return rc;
750}
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400753CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 LOGOFF_ANDX_REQ *pSMB;
756 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Joe Perchesf96637b2013-05-04 22:12:25 -0500758 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500759
760 /*
761 * BB: do we need to check validity of ses and server? They should
762 * always be valid since we have an active reference. If not, that
763 * should probably be a BUG()
764 */
765 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return -EIO;
767
Steve Frenchd7b619c2010-02-25 05:36:46 +0000768 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000769 if (ses->need_reconnect)
770 goto session_already_dead; /* no need to send SMBlogoff if uid
771 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
773 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000774 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return rc;
776 }
777
Pavel Shilovsky88257362012-05-23 14:01:59 +0400778 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700779
Steve French96daf2b2011-05-27 04:34:02 +0000780 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
782 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 pSMB->hdr.Uid = ses->Suid;
785
786 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400787 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000788session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000789 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000792 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 error */
794 if (rc == -EAGAIN)
795 rc = 0;
796 return rc;
797}
798
799int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400800CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
801 const char *fileName, __u16 type,
802 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000803{
804 TRANSACTION2_SPI_REQ *pSMB = NULL;
805 TRANSACTION2_SPI_RSP *pSMBr = NULL;
806 struct unlink_psx_rq *pRqD;
807 int name_len;
808 int rc = 0;
809 int bytes_returned = 0;
810 __u16 params, param_offset, offset, byte_count;
811
Joe Perchesf96637b2013-05-04 22:12:25 -0500812 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000813PsxDelete:
814 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
815 (void **) &pSMBr);
816 if (rc)
817 return rc;
818
819 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
820 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600821 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
822 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000823 name_len++; /* trailing null */
824 name_len *= 2;
825 } else { /* BB add path length overrun check */
826 name_len = strnlen(fileName, PATH_MAX);
827 name_len++; /* trailing null */
828 strncpy(pSMB->FileName, fileName, name_len);
829 }
830
831 params = 6 + name_len;
832 pSMB->MaxParameterCount = cpu_to_le16(2);
833 pSMB->MaxDataCount = 0; /* BB double check this with jra */
834 pSMB->MaxSetupCount = 0;
835 pSMB->Reserved = 0;
836 pSMB->Flags = 0;
837 pSMB->Timeout = 0;
838 pSMB->Reserved2 = 0;
839 param_offset = offsetof(struct smb_com_transaction2_spi_req,
840 InformationLevel) - 4;
841 offset = param_offset + params;
842
843 /* Setup pointer to Request Data (inode type) */
844 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
845 pRqD->type = cpu_to_le16(type);
846 pSMB->ParameterOffset = cpu_to_le16(param_offset);
847 pSMB->DataOffset = cpu_to_le16(offset);
848 pSMB->SetupCount = 1;
849 pSMB->Reserved3 = 0;
850 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
851 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
852
853 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
854 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
855 pSMB->ParameterCount = cpu_to_le16(params);
856 pSMB->TotalParameterCount = pSMB->ParameterCount;
857 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
858 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000859 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000860 pSMB->ByteCount = cpu_to_le16(byte_count);
861 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
862 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000863 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500864 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000865 cifs_buf_release(pSMB);
866
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400867 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000868
869 if (rc == -EAGAIN)
870 goto PsxDelete;
871
872 return rc;
873}
874
875int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700876CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
877 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
879 DELETE_FILE_REQ *pSMB = NULL;
880 DELETE_FILE_RSP *pSMBr = NULL;
881 int rc = 0;
882 int bytes_returned;
883 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700884 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886DelFileRetry:
887 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
888 (void **) &pSMBr);
889 if (rc)
890 return rc;
891
892 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700893 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
894 PATH_MAX, cifs_sb->local_nls,
895 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 name_len++; /* trailing null */
897 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700898 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700899 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700901 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903 pSMB->SearchAttributes =
904 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
905 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000906 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 pSMB->ByteCount = cpu_to_le16(name_len + 1);
908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400910 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000911 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500912 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 cifs_buf_release(pSMB);
915 if (rc == -EAGAIN)
916 goto DelFileRetry;
917
918 return rc;
919}
920
921int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400922CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
923 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
925 DELETE_DIRECTORY_REQ *pSMB = NULL;
926 DELETE_DIRECTORY_RSP *pSMBr = NULL;
927 int rc = 0;
928 int bytes_returned;
929 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400930 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Joe Perchesf96637b2013-05-04 22:12:25 -0500932 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933RmDirRetry:
934 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
938
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400940 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
941 PATH_MAX, cifs_sb->local_nls,
942 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
944 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700945 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400946 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400948 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 }
950
951 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000952 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400956 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000957 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500958 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto RmDirRetry;
963 return rc;
964}
965
966int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300967CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
968 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 int rc = 0;
971 CREATE_DIRECTORY_REQ *pSMB = NULL;
972 CREATE_DIRECTORY_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300975 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Joe Perchesf96637b2013-05-04 22:12:25 -0500977 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978MkDirRetry:
979 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
980 (void **) &pSMBr);
981 if (rc)
982 return rc;
983
984 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600985 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300986 PATH_MAX, cifs_sb->local_nls,
987 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 name_len++; /* trailing null */
989 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700990 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 name_len = strnlen(name, PATH_MAX);
992 name_len++; /* trailing null */
993 strncpy(pSMB->DirName, name, name_len);
994 }
995
996 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000997 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 pSMB->ByteCount = cpu_to_le16(name_len + 1);
999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001001 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001002 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001003 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 cifs_buf_release(pSMB);
1006 if (rc == -EAGAIN)
1007 goto MkDirRetry;
1008 return rc;
1009}
1010
Steve French2dd29d32007-04-23 22:07:35 +00001011int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001012CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1013 __u32 posix_flags, __u64 mode, __u16 *netfid,
1014 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1015 const char *name, const struct nls_table *nls_codepage,
1016 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001017{
1018 TRANSACTION2_SPI_REQ *pSMB = NULL;
1019 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1020 int name_len;
1021 int rc = 0;
1022 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001023 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001024 OPEN_PSX_REQ *pdata;
1025 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001026
Joe Perchesf96637b2013-05-04 22:12:25 -05001027 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001028PsxCreat:
1029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1030 (void **) &pSMBr);
1031 if (rc)
1032 return rc;
1033
1034 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1035 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001036 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1037 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001038 name_len++; /* trailing null */
1039 name_len *= 2;
1040 } else { /* BB improve the check for buffer overruns BB */
1041 name_len = strnlen(name, PATH_MAX);
1042 name_len++; /* trailing null */
1043 strncpy(pSMB->FileName, name, name_len);
1044 }
1045
1046 params = 6 + name_len;
1047 count = sizeof(OPEN_PSX_REQ);
1048 pSMB->MaxParameterCount = cpu_to_le16(2);
1049 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1050 pSMB->MaxSetupCount = 0;
1051 pSMB->Reserved = 0;
1052 pSMB->Flags = 0;
1053 pSMB->Timeout = 0;
1054 pSMB->Reserved2 = 0;
1055 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001056 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001057 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001058 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001059 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001060 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001061 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001062 pdata->OpenFlags = cpu_to_le32(*pOplock);
1063 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1064 pSMB->DataOffset = cpu_to_le16(offset);
1065 pSMB->SetupCount = 1;
1066 pSMB->Reserved3 = 0;
1067 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1068 byte_count = 3 /* pad */ + params + count;
1069
1070 pSMB->DataCount = cpu_to_le16(count);
1071 pSMB->ParameterCount = cpu_to_le16(params);
1072 pSMB->TotalDataCount = pSMB->DataCount;
1073 pSMB->TotalParameterCount = pSMB->ParameterCount;
1074 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1075 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001076 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001077 pSMB->ByteCount = cpu_to_le16(byte_count);
1078 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1079 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1080 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001081 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001082 goto psx_create_err;
1083 }
1084
Joe Perchesf96637b2013-05-04 22:12:25 -05001085 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001086 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1087
Jeff Layton820a8032011-05-04 08:05:26 -04001088 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001089 rc = -EIO; /* bad smb */
1090 goto psx_create_err;
1091 }
1092
1093 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001094 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001095 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001096
Steve French2dd29d32007-04-23 22:07:35 +00001097 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001098 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001099 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1100 /* Let caller know file was created so we can set the mode. */
1101 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001102 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001103 *pOplock |= CIFS_CREATE_ACTION;
1104 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001105 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1106 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001107 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001108 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001109 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001110 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001111 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001112 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001113 goto psx_create_err;
1114 }
Steve French50c2f752007-07-13 00:33:32 +00001115 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001116 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001117 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001118 }
Steve French2dd29d32007-04-23 22:07:35 +00001119
1120psx_create_err:
1121 cifs_buf_release(pSMB);
1122
Steve French65bc98b2009-07-10 15:27:25 +00001123 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001124 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001125 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001126 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001127
1128 if (rc == -EAGAIN)
1129 goto PsxCreat;
1130
Steve French50c2f752007-07-13 00:33:32 +00001131 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001132}
1133
Steve Frencha9d02ad2005-08-24 23:06:05 -07001134static __u16 convert_disposition(int disposition)
1135{
1136 __u16 ofun = 0;
1137
1138 switch (disposition) {
1139 case FILE_SUPERSEDE:
1140 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1141 break;
1142 case FILE_OPEN:
1143 ofun = SMBOPEN_OAPPEND;
1144 break;
1145 case FILE_CREATE:
1146 ofun = SMBOPEN_OCREATE;
1147 break;
1148 case FILE_OPEN_IF:
1149 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1150 break;
1151 case FILE_OVERWRITE:
1152 ofun = SMBOPEN_OTRUNC;
1153 break;
1154 case FILE_OVERWRITE_IF:
1155 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1156 break;
1157 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001158 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001159 ofun = SMBOPEN_OAPPEND; /* regular open */
1160 }
1161 return ofun;
1162}
1163
Jeff Layton35fc37d2008-05-14 10:22:03 -07001164static int
1165access_flags_to_smbopen_mode(const int access_flags)
1166{
1167 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1168
1169 if (masked_flags == GENERIC_READ)
1170 return SMBOPEN_READ;
1171 else if (masked_flags == GENERIC_WRITE)
1172 return SMBOPEN_WRITE;
1173
1174 /* just go for read/write */
1175 return SMBOPEN_READWRITE;
1176}
1177
Steve Frencha9d02ad2005-08-24 23:06:05 -07001178int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001179SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001181 const int access_flags, const int create_options, __u16 *netfid,
1182 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183 const struct nls_table *nls_codepage, int remap)
1184{
1185 int rc = -EACCES;
1186 OPENX_REQ *pSMB = NULL;
1187 OPENX_RSP *pSMBr = NULL;
1188 int bytes_returned;
1189 int name_len;
1190 __u16 count;
1191
1192OldOpenRetry:
1193 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1194 (void **) &pSMBr);
1195 if (rc)
1196 return rc;
1197
1198 pSMB->AndXCommand = 0xFF; /* none */
1199
1200 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1201 count = 1; /* account for one byte pad to word boundary */
1202 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001203 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1204 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001205 name_len++; /* trailing null */
1206 name_len *= 2;
1207 } else { /* BB improve check for buffer overruns BB */
1208 count = 0; /* no pad */
1209 name_len = strnlen(fileName, PATH_MAX);
1210 name_len++; /* trailing null */
1211 strncpy(pSMB->fileName, fileName, name_len);
1212 }
1213 if (*pOplock & REQ_OPLOCK)
1214 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001215 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001217
Steve Frencha9d02ad2005-08-24 23:06:05 -07001218 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001219 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1221 /* set file as system file if special file such
1222 as fifo and server expecting SFU style and
1223 no Unix extensions */
1224
Steve French790fe572007-07-07 19:25:05 +00001225 if (create_options & CREATE_OPTION_SPECIAL)
1226 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001227 else /* BB FIXME BB */
1228 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
Jeff Layton67750fb2008-05-09 22:28:02 +00001230 if (create_options & CREATE_OPTION_READONLY)
1231 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232
1233 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001234/* pSMB->CreateOptions = cpu_to_le32(create_options &
1235 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001237
1238 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001239 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001241 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242
1243 pSMB->ByteCount = cpu_to_le16(count);
1244 /* long_op set to 1 to allow for oplock break timeouts */
1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001246 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001247 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001249 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 } else {
1251 /* BB verify if wct == 15 */
1252
Steve French582d21e2008-05-13 04:54:12 +00001253/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001259/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1262
Steve French790fe572007-07-07 19:25:05 +00001263 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001275 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 }
1277 }
1278
1279 cifs_buf_release(pSMB);
1280 if (rc == -EAGAIN)
1281 goto OldOpenRetry;
1282 return rc;
1283}
1284
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001286CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001288 const int access_flags, const int create_options, __u16 *netfid,
1289 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001290 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291{
1292 int rc = -EACCES;
1293 OPEN_REQ *pSMB = NULL;
1294 OPEN_RSP *pSMBr = NULL;
1295 int bytes_returned;
1296 int name_len;
1297 __u16 count;
1298
1299openRetry:
1300 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1301 (void **) &pSMBr);
1302 if (rc)
1303 return rc;
1304
1305 pSMB->AndXCommand = 0xFF; /* none */
1306
1307 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1308 count = 1; /* account for one byte pad to word boundary */
1309 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001310 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1311 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 name_len++; /* trailing null */
1313 name_len *= 2;
1314 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001315 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 count = 0; /* no pad */
1317 name_len = strnlen(fileName, PATH_MAX);
1318 name_len++; /* trailing null */
1319 pSMB->NameLength = cpu_to_le16(name_len);
1320 strncpy(pSMB->fileName, fileName, name_len);
1321 }
1322 if (*pOplock & REQ_OPLOCK)
1323 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001324 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1327 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001328 /* set file as system file if special file such
1329 as fifo and server expecting SFU style and
1330 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001331 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001332 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1333 else
1334 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 /* XP does not handle ATTR_POSIX_SEMANTICS */
1337 /* but it helps speed up case sensitive checks for other
1338 servers such as Samba */
1339 if (tcon->ses->capabilities & CAP_UNIX)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1341
Jeff Layton67750fb2008-05-09 22:28:02 +00001342 if (create_options & CREATE_OPTION_READONLY)
1343 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1344
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1346 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001347 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001348 /* BB Expirement with various impersonation levels and verify */
1349 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->SecurityFlags =
1351 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1352
1353 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001354 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
1356 pSMB->ByteCount = cpu_to_le16(count);
1357 /* long_op set to 1 to allow for oplock break timeouts */
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001359 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001360 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001362 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 } else {
Steve French09d1db52005-04-28 22:41:08 -07001364 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1366 /* Let caller know file was created so we can set the mode. */
1367 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001368 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001369 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001370 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001371 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1372 36 /* CreationTime to Attributes */);
1373 /* the file_info buf is endian converted by caller */
1374 pfile_info->AllocationSize = pSMBr->AllocationSize;
1375 pfile_info->EndOfFile = pSMBr->EndOfFile;
1376 pfile_info->NumberOfLinks = cpu_to_le32(1);
1377 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 cifs_buf_release(pSMB);
1382 if (rc == -EAGAIN)
1383 goto openRetry;
1384 return rc;
1385}
1386
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001387/*
1388 * Discard any remaining data in the current SMB. To do this, we borrow the
1389 * current bigbuf.
1390 */
1391static int
1392cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1393{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001394 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001395 int remaining = rfclen + 4 - server->total_read;
1396 struct cifs_readdata *rdata = mid->callback_data;
1397
1398 while (remaining > 0) {
1399 int length;
1400
1401 length = cifs_read_from_socket(server, server->bigbuf,
1402 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001403 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001404 if (length < 0)
1405 return length;
1406 server->total_read += length;
1407 remaining -= length;
1408 }
1409
1410 dequeue_mid(mid, rdata->result);
1411 return 0;
1412}
1413
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001414int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001415cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1416{
1417 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001418 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001419 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001420 char *buf = server->smallbuf;
1421 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001422
Joe Perchesf96637b2013-05-04 22:12:25 -05001423 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1424 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425
1426 /*
1427 * read the rest of READ_RSP header (sans Data array), or whatever we
1428 * can if there's not enough data. At this point, we've read down to
1429 * the Mid.
1430 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001431 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001432 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001433
Jeff Layton58195752012-09-19 06:22:34 -07001434 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1435 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001436
Jeff Layton58195752012-09-19 06:22:34 -07001437 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438 if (length < 0)
1439 return length;
1440 server->total_read += length;
1441
1442 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001443 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001444 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001445 cifs_dbg(FYI, "%s: server returned error %d\n",
1446 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001447 return cifs_readv_discard(server, mid);
1448 }
1449
1450 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001451 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001452 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1453 __func__, server->total_read,
1454 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001455 rdata->result = -EIO;
1456 return cifs_readv_discard(server, mid);
1457 }
1458
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001459 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001460 if (data_offset < server->total_read) {
1461 /*
1462 * win2k8 sometimes sends an offset of 0 when the read
1463 * is beyond the EOF. Treat it as if the data starts just after
1464 * the header.
1465 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001466 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1467 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001468 data_offset = server->total_read;
1469 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1470 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001471 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1472 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001473 rdata->result = -EIO;
1474 return cifs_readv_discard(server, mid);
1475 }
1476
Joe Perchesf96637b2013-05-04 22:12:25 -05001477 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1478 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479
1480 len = data_offset - server->total_read;
1481 if (len > 0) {
1482 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001483 rdata->iov.iov_base = buf + server->total_read;
1484 rdata->iov.iov_len = len;
1485 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001486 if (length < 0)
1487 return length;
1488 server->total_read += length;
1489 }
1490
1491 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001492 rdata->iov.iov_base = buf;
1493 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001494 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1495 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001496
1497 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001498 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001499 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001500 /* data_len is corrupt -- discard frame */
1501 rdata->result = -EIO;
1502 return cifs_readv_discard(server, mid);
1503 }
1504
Jeff Layton8321fec2012-09-19 06:22:32 -07001505 length = rdata->read_into_pages(server, rdata, data_len);
1506 if (length < 0)
1507 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001508
Jeff Layton8321fec2012-09-19 06:22:32 -07001509 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001510 rdata->bytes = length;
1511
Joe Perchesf96637b2013-05-04 22:12:25 -05001512 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1513 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514
1515 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001516 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001517 return cifs_readv_discard(server, mid);
1518
1519 dequeue_mid(mid, false);
1520 return length;
1521}
1522
1523static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524cifs_readv_callback(struct mid_q_entry *mid)
1525{
1526 struct cifs_readdata *rdata = mid->callback_data;
1527 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1528 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001529 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1530 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001531 .rq_pages = rdata->pages,
1532 .rq_npages = rdata->nr_pages,
1533 .rq_pagesz = rdata->pagesz,
1534 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001535
Joe Perchesf96637b2013-05-04 22:12:25 -05001536 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1537 __func__, mid->mid, mid->mid_state, rdata->result,
1538 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001539
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001540 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541 case MID_RESPONSE_RECEIVED:
1542 /* result already set, check signature */
1543 if (server->sec_mode &
1544 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001545 int rc = 0;
1546
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001547 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001548 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001549 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001550 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1551 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001552 }
1553 /* FIXME: should this be counted toward the initiating task? */
1554 task_io_account_read(rdata->bytes);
1555 cifs_stats_bytes_read(tcon, rdata->bytes);
1556 break;
1557 case MID_REQUEST_SUBMITTED:
1558 case MID_RETRY_NEEDED:
1559 rdata->result = -EAGAIN;
1560 break;
1561 default:
1562 rdata->result = -EIO;
1563 }
1564
Jeff Laytonda472fc2012-03-23 14:40:53 -04001565 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001566 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001567 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001568}
1569
1570/* cifs_async_readv - send an async write, and set up mid to handle result */
1571int
1572cifs_async_readv(struct cifs_readdata *rdata)
1573{
1574 int rc;
1575 READ_REQ *smb = NULL;
1576 int wct;
1577 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001578 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001579 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001580
Joe Perchesf96637b2013-05-04 22:12:25 -05001581 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1582 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001583
1584 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1585 wct = 12;
1586 else {
1587 wct = 10; /* old style read */
1588 if ((rdata->offset >> 32) > 0) {
1589 /* can not handle this big offset for old */
1590 return -EIO;
1591 }
1592 }
1593
1594 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1595 if (rc)
1596 return rc;
1597
1598 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1599 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1600
1601 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001602 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001603 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1604 if (wct == 12)
1605 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1606 smb->Remaining = 0;
1607 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1608 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1609 if (wct == 12)
1610 smb->ByteCount = 0;
1611 else {
1612 /* old style read */
1613 struct smb_com_readx_req *smbr =
1614 (struct smb_com_readx_req *)smb;
1615 smbr->ByteCount = 0;
1616 }
1617
1618 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001619 rdata->iov.iov_base = smb;
1620 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001621
Jeff Layton6993f742012-05-16 07:13:17 -04001622 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001623 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1624 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625
1626 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001627 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001628 else
1629 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630
1631 cifs_small_buf_release(smb);
1632 return rc;
1633}
1634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001636CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1637 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638{
1639 int rc = -EACCES;
1640 READ_REQ *pSMB = NULL;
1641 READ_RSP *pSMBr = NULL;
1642 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001643 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001644 int resp_buf_type = 0;
1645 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001646 __u32 pid = io_parms->pid;
1647 __u16 netfid = io_parms->netfid;
1648 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001649 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001650 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Joe Perchesf96637b2013-05-04 22:12:25 -05001652 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001653 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001654 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001655 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001656 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001657 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001658 /* can not handle this big offset for old */
1659 return -EIO;
1660 }
1661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
1663 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001664 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 if (rc)
1666 return rc;
1667
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001668 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1669 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 /* tcon and ses pointer are checked in smb_init */
1672 if (tcon->ses->server == NULL)
1673 return -ECONNABORTED;
1674
Steve Frenchec637e32005-12-12 20:53:18 -08001675 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001677 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001678 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001679 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 pSMB->Remaining = 0;
1682 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1683 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001684 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001685 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1686 else {
1687 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001688 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001689 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001690 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001691 }
Steve Frenchec637e32005-12-12 20:53:18 -08001692
1693 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001694 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001695 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001696 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001697 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001698 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001700 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 } else {
1702 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1703 data_length = data_length << 16;
1704 data_length += le16_to_cpu(pSMBr->DataLength);
1705 *nbytes = data_length;
1706
1707 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001708 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001710 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001711 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 rc = -EIO;
1713 *nbytes = 0;
1714 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001715 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001716 le16_to_cpu(pSMBr->DataOffset);
1717/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001718 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001719 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001720 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001721 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001722 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 }
1724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
Steve French4b8f9302006-02-26 16:41:18 +00001726/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001727 if (*buf) {
1728 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001729 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001730 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001731 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001732 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001733 /* return buffer to caller to free */
1734 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001735 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001736 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001737 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001738 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001739 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001740
1741 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 since file handle passed in no longer valid */
1743 return rc;
1744}
1745
Steve Frenchec637e32005-12-12 20:53:18 -08001746
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001748CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001749 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001750 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751{
1752 int rc = -EACCES;
1753 WRITE_REQ *pSMB = NULL;
1754 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001755 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 __u32 bytes_sent;
1757 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001758 __u32 pid = io_parms->pid;
1759 __u16 netfid = io_parms->netfid;
1760 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001761 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001762 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
Steve Frencha24e2d72010-04-03 17:20:21 +00001764 *nbytes = 0;
1765
Joe Perchesf96637b2013-05-04 22:12:25 -05001766 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001767 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001768 return -ECONNABORTED;
1769
Steve French790fe572007-07-07 19:25:05 +00001770 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001771 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001772 else {
Steve French1c955182005-08-30 20:58:07 -07001773 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001774 if ((offset >> 32) > 0) {
1775 /* can not handle big offset for old srv */
1776 return -EIO;
1777 }
1778 }
Steve French1c955182005-08-30 20:58:07 -07001779
1780 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 (void **) &pSMBr);
1782 if (rc)
1783 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001784
1785 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1786 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 /* tcon and ses pointer are checked in smb_init */
1789 if (tcon->ses->server == NULL)
1790 return -ECONNABORTED;
1791
1792 pSMB->AndXCommand = 0xFF; /* none */
1793 pSMB->Fid = netfid;
1794 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001795 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001796 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001797
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 pSMB->Reserved = 0xFFFFFFFF;
1799 pSMB->WriteMode = 0;
1800 pSMB->Remaining = 0;
1801
Steve French50c2f752007-07-13 00:33:32 +00001802 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 can send more if LARGE_WRITE_X capability returned by the server and if
1804 our buffer is big enough or if we convert to iovecs on socket writes
1805 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001806 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1808 } else {
1809 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1810 & ~0xFF;
1811 }
1812
1813 if (bytes_sent > count)
1814 bytes_sent = count;
1815 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001816 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001817 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001818 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001819 else if (ubuf) {
1820 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 cifs_buf_release(pSMB);
1822 return -EFAULT;
1823 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001824 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 /* No buffer */
1826 cifs_buf_release(pSMB);
1827 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001828 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001829 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001830 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001831 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001832 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001833
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1835 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001836 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001837
Steve French790fe572007-07-07 19:25:05 +00001838 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001839 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001840 else { /* old style write has byte count 4 bytes earlier
1841 so 4 bytes pad */
1842 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001843 (struct smb_com_writex_req *)pSMB;
1844 pSMBW->ByteCount = cpu_to_le16(byte_count);
1845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1848 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001849 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001851 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 } else {
1853 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1854 *nbytes = (*nbytes) << 16;
1855 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301856
1857 /*
1858 * Mask off high 16 bits when bytes written as returned by the
1859 * server is greater than bytes requested by the client. Some
1860 * OS/2 servers are known to set incorrect CountHigh values.
1861 */
1862 if (*nbytes > count)
1863 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 }
1865
1866 cifs_buf_release(pSMB);
1867
Steve French50c2f752007-07-13 00:33:32 +00001868 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 since file handle passed in no longer valid */
1870
1871 return rc;
1872}
1873
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001874void
1875cifs_writedata_release(struct kref *refcount)
1876{
1877 struct cifs_writedata *wdata = container_of(refcount,
1878 struct cifs_writedata, refcount);
1879
1880 if (wdata->cfile)
1881 cifsFileInfo_put(wdata->cfile);
1882
1883 kfree(wdata);
1884}
1885
1886/*
1887 * Write failed with a retryable error. Resend the write request. It's also
1888 * possible that the page was redirtied so re-clean the page.
1889 */
1890static void
1891cifs_writev_requeue(struct cifs_writedata *wdata)
1892{
1893 int i, rc;
1894 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001895 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001896
1897 for (i = 0; i < wdata->nr_pages; i++) {
1898 lock_page(wdata->pages[i]);
1899 clear_page_dirty_for_io(wdata->pages[i]);
1900 }
1901
1902 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001903 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1904 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001905 } while (rc == -EAGAIN);
1906
1907 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001908 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001909 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001910 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001911 end_page_writeback(wdata->pages[i]);
1912 page_cache_release(wdata->pages[i]);
1913 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001914 }
1915
1916 mapping_set_error(inode->i_mapping, rc);
1917 kref_put(&wdata->refcount, cifs_writedata_release);
1918}
1919
Jeff Laytonc2e87642012-03-23 14:40:55 -04001920void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001921cifs_writev_complete(struct work_struct *work)
1922{
1923 struct cifs_writedata *wdata = container_of(work,
1924 struct cifs_writedata, work);
1925 struct inode *inode = wdata->cfile->dentry->d_inode;
1926 int i = 0;
1927
1928 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001929 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001930 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001931 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001932 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1933 wdata->bytes);
1934 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1935 return cifs_writev_requeue(wdata);
1936
1937 for (i = 0; i < wdata->nr_pages; i++) {
1938 struct page *page = wdata->pages[i];
1939 if (wdata->result == -EAGAIN)
1940 __set_page_dirty_nobuffers(page);
1941 else if (wdata->result < 0)
1942 SetPageError(page);
1943 end_page_writeback(page);
1944 page_cache_release(page);
1945 }
1946 if (wdata->result != -EAGAIN)
1947 mapping_set_error(inode->i_mapping, wdata->result);
1948 kref_put(&wdata->refcount, cifs_writedata_release);
1949}
1950
1951struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001952cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001953{
1954 struct cifs_writedata *wdata;
1955
1956 /* this would overflow */
1957 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001958 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001959 return NULL;
1960 }
1961
1962 /* writedata + number of page pointers */
1963 wdata = kzalloc(sizeof(*wdata) +
1964 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1965 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001966 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001967 INIT_LIST_HEAD(&wdata->list);
1968 init_completion(&wdata->done);
1969 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001970 }
1971 return wdata;
1972}
1973
1974/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001975 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976 * workqueue completion task.
1977 */
1978static void
1979cifs_writev_callback(struct mid_q_entry *mid)
1980{
1981 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001982 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001983 unsigned int written;
1984 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1985
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001986 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001987 case MID_RESPONSE_RECEIVED:
1988 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1989 if (wdata->result != 0)
1990 break;
1991
1992 written = le16_to_cpu(smb->CountHigh);
1993 written <<= 16;
1994 written += le16_to_cpu(smb->Count);
1995 /*
1996 * Mask off high 16 bits when bytes written as returned
1997 * by the server is greater than bytes requested by the
1998 * client. OS/2 servers are known to set incorrect
1999 * CountHigh values.
2000 */
2001 if (written > wdata->bytes)
2002 written &= 0xFFFF;
2003
2004 if (written < wdata->bytes)
2005 wdata->result = -ENOSPC;
2006 else
2007 wdata->bytes = written;
2008 break;
2009 case MID_REQUEST_SUBMITTED:
2010 case MID_RETRY_NEEDED:
2011 wdata->result = -EAGAIN;
2012 break;
2013 default:
2014 wdata->result = -EIO;
2015 break;
2016 }
2017
Jeff Laytonda472fc2012-03-23 14:40:53 -04002018 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002019 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002020 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002021}
2022
2023/* cifs_async_writev - send an async write, and set up mid to handle result */
2024int
2025cifs_async_writev(struct cifs_writedata *wdata)
2026{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002027 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002028 WRITE_REQ *smb = NULL;
2029 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002030 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002031 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002032 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002033
2034 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2035 wct = 14;
2036 } else {
2037 wct = 12;
2038 if (wdata->offset >> 32 > 0) {
2039 /* can not handle big offset for old srv */
2040 return -EIO;
2041 }
2042 }
2043
2044 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2045 if (rc)
2046 goto async_writev_out;
2047
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002048 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2049 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002050
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002051 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002052 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002053 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2054 if (wct == 14)
2055 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2056 smb->Reserved = 0xFFFFFFFF;
2057 smb->WriteMode = 0;
2058 smb->Remaining = 0;
2059
2060 smb->DataOffset =
2061 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2062
2063 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002064 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2065 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002066
Jeff Laytoneddb0792012-09-18 16:20:35 -07002067 rqst.rq_iov = &iov;
2068 rqst.rq_nvec = 1;
2069 rqst.rq_pages = wdata->pages;
2070 rqst.rq_npages = wdata->nr_pages;
2071 rqst.rq_pagesz = wdata->pagesz;
2072 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002073
Joe Perchesf96637b2013-05-04 22:12:25 -05002074 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2075 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076
2077 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2078 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2079
2080 if (wct == 14) {
2081 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2082 put_bcc(wdata->bytes + 1, &smb->hdr);
2083 } else {
2084 /* wct == 12 */
2085 struct smb_com_writex_req *smbw =
2086 (struct smb_com_writex_req *)smb;
2087 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2088 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002089 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002090 }
2091
2092 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002093 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2094 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095
2096 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002097 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002098 else
2099 kref_put(&wdata->refcount, cifs_writedata_release);
2100
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101async_writev_out:
2102 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002103 return rc;
2104}
2105
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002106int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002107CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002108 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109{
2110 int rc = -EACCES;
2111 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002112 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002113 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002114 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002115 __u32 pid = io_parms->pid;
2116 __u16 netfid = io_parms->netfid;
2117 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002118 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002119 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002121 *nbytes = 0;
2122
Joe Perchesf96637b2013-05-04 22:12:25 -05002123 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002124
Steve French4c3130e2008-12-09 00:28:16 +00002125 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002126 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002127 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002128 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002129 if ((offset >> 32) > 0) {
2130 /* can not handle big offset for old srv */
2131 return -EIO;
2132 }
2133 }
Steve French8cc64c62005-10-03 13:49:43 -07002134 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (rc)
2136 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002137
2138 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2139 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 /* tcon and ses pointer are checked in smb_init */
2142 if (tcon->ses->server == NULL)
2143 return -ECONNABORTED;
2144
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002145 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 pSMB->Fid = netfid;
2147 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002148 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002149 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 pSMB->Reserved = 0xFFFFFFFF;
2151 pSMB->WriteMode = 0;
2152 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002153
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002155 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
Steve French3e844692005-10-03 13:37:24 -07002157 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2158 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002159 /* header + 1 byte pad */
2160 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002161 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002162 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002163 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002164 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002165 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002166 pSMB->ByteCount = cpu_to_le16(count + 1);
2167 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002168 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002169 (struct smb_com_writex_req *)pSMB;
2170 pSMBW->ByteCount = cpu_to_le16(count + 5);
2171 }
Steve French3e844692005-10-03 13:37:24 -07002172 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002173 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002174 iov[0].iov_len = smb_hdr_len + 4;
2175 else /* wct == 12 pad bigger by four bytes */
2176 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002177
Steve French3e844692005-10-03 13:37:24 -07002178
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002179 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002180 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002182 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002183 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002184 /* presumably this can not happen, but best to be safe */
2185 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002186 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002187 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002188 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2189 *nbytes = (*nbytes) << 16;
2190 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302191
2192 /*
2193 * Mask off high 16 bits when bytes written as returned by the
2194 * server is greater than bytes requested by the client. OS/2
2195 * servers are known to set incorrect CountHigh values.
2196 */
2197 if (*nbytes > count)
2198 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Steve French4b8f9302006-02-26 16:41:18 +00002201/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002202 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002203 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002204 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002205 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Steve French50c2f752007-07-13 00:33:32 +00002207 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 since file handle passed in no longer valid */
2209
2210 return rc;
2211}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002212
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002213int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2214 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002215 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2216{
2217 int rc = 0;
2218 LOCK_REQ *pSMB = NULL;
2219 struct kvec iov[2];
2220 int resp_buf_type;
2221 __u16 count;
2222
Joe Perchesf96637b2013-05-04 22:12:25 -05002223 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2224 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002225
2226 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2227 if (rc)
2228 return rc;
2229
2230 pSMB->Timeout = 0;
2231 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2232 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2233 pSMB->LockType = lock_type;
2234 pSMB->AndXCommand = 0xFF; /* none */
2235 pSMB->Fid = netfid; /* netfid stays le */
2236
2237 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2238 inc_rfc1001_len(pSMB, count);
2239 pSMB->ByteCount = cpu_to_le16(count);
2240
2241 iov[0].iov_base = (char *)pSMB;
2242 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2243 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2244 iov[1].iov_base = (char *)buf;
2245 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2246
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002247 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002248 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2249 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002250 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002251
2252 return rc;
2253}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002254
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002256CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002257 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002259 const __u32 numLock, const __u8 lockType,
2260 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261{
2262 int rc = 0;
2263 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002264/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002266 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 __u16 count;
2268
Joe Perchesf96637b2013-05-04 22:12:25 -05002269 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2270 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002271 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2272
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 if (rc)
2274 return rc;
2275
Steve French790fe572007-07-07 19:25:05 +00002276 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002277 /* no response expected */
2278 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002280 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002281 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2283 } else {
2284 pSMB->Timeout = 0;
2285 }
2286
2287 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2288 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2289 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002290 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 pSMB->AndXCommand = 0xFF; /* none */
2292 pSMB->Fid = smb_file_id; /* netfid stays le */
2293
Steve French790fe572007-07-07 19:25:05 +00002294 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002295 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 /* BB where to store pid high? */
2297 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2298 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2299 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2300 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2301 count = sizeof(LOCKING_ANDX_RANGE);
2302 } else {
2303 /* oplock break */
2304 count = 0;
2305 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002306 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 pSMB->ByteCount = cpu_to_le16(count);
2308
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002309 if (waitFlag) {
2310 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002311 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002312 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002313 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002314 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002315 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002316 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002317 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002318 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002319 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
Steve French50c2f752007-07-13 00:33:32 +00002321 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 since file handle passed in no longer valid */
2323 return rc;
2324}
2325
2326int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002327CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002328 const __u16 smb_file_id, const __u32 netpid,
2329 const loff_t start_offset, const __u64 len,
2330 struct file_lock *pLockData, const __u16 lock_type,
2331 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002332{
2333 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2334 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002335 struct cifs_posix_lock *parm_data;
2336 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002337 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002338 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002339 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002340 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002341 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002342
Joe Perchesf96637b2013-05-04 22:12:25 -05002343 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002344
Steve French08547b02006-02-28 22:39:25 +00002345 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2346
2347 if (rc)
2348 return rc;
2349
2350 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2351
Steve French50c2f752007-07-13 00:33:32 +00002352 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002353 pSMB->MaxSetupCount = 0;
2354 pSMB->Reserved = 0;
2355 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002356 pSMB->Reserved2 = 0;
2357 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2358 offset = param_offset + params;
2359
Steve French08547b02006-02-28 22:39:25 +00002360 count = sizeof(struct cifs_posix_lock);
2361 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002362 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002363 pSMB->SetupCount = 1;
2364 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002365 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002366 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2367 else
2368 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2369 byte_count = 3 /* pad */ + params + count;
2370 pSMB->DataCount = cpu_to_le16(count);
2371 pSMB->ParameterCount = cpu_to_le16(params);
2372 pSMB->TotalDataCount = pSMB->DataCount;
2373 pSMB->TotalParameterCount = pSMB->ParameterCount;
2374 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002375 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002376 (((char *) &pSMB->hdr.Protocol) + offset);
2377
2378 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002379 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002380 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002381 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002382 pSMB->Timeout = cpu_to_le32(-1);
2383 } else
2384 pSMB->Timeout = 0;
2385
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002386 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002387 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002388 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002389
2390 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002391 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002392 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2393 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002394 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002395 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002396 if (waitFlag) {
2397 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2398 (struct smb_hdr *) pSMBr, &bytes_returned);
2399 } else {
Steve French133672e2007-11-13 22:41:37 +00002400 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002401 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002402 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2403 &resp_buf_type, timeout);
2404 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2405 not try to free it twice below on exit */
2406 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002407 }
2408
Steve French08547b02006-02-28 22:39:25 +00002409 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002410 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002411 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002412 /* lock structure can be returned on get */
2413 __u16 data_offset;
2414 __u16 data_count;
2415 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002416
Jeff Layton820a8032011-05-04 08:05:26 -04002417 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002418 rc = -EIO; /* bad smb */
2419 goto plk_err_exit;
2420 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002421 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2422 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002423 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002424 rc = -EIO;
2425 goto plk_err_exit;
2426 }
2427 parm_data = (struct cifs_posix_lock *)
2428 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002429 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002430 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002431 else {
2432 if (parm_data->lock_type ==
2433 __constant_cpu_to_le16(CIFS_RDLCK))
2434 pLockData->fl_type = F_RDLCK;
2435 else if (parm_data->lock_type ==
2436 __constant_cpu_to_le16(CIFS_WRLCK))
2437 pLockData->fl_type = F_WRLCK;
2438
Steve French5443d132011-03-13 05:08:25 +00002439 pLockData->fl_start = le64_to_cpu(parm_data->start);
2440 pLockData->fl_end = pLockData->fl_start +
2441 le64_to_cpu(parm_data->length) - 1;
2442 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002443 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002444 }
Steve French50c2f752007-07-13 00:33:32 +00002445
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002446plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002447 if (pSMB)
2448 cifs_small_buf_release(pSMB);
2449
Steve French133672e2007-11-13 22:41:37 +00002450 if (resp_buf_type == CIFS_SMALL_BUFFER)
2451 cifs_small_buf_release(iov[0].iov_base);
2452 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2453 cifs_buf_release(iov[0].iov_base);
2454
Steve French08547b02006-02-28 22:39:25 +00002455 /* Note: On -EAGAIN error only caller can retry on handle based calls
2456 since file handle passed in no longer valid */
2457
2458 return rc;
2459}
2460
2461
2462int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002463CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464{
2465 int rc = 0;
2466 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002467 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
2469/* do not retry on dead session on close */
2470 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002471 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 return 0;
2473 if (rc)
2474 return rc;
2475
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002477 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002479 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002480 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002482 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002484 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 }
2486 }
2487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002489 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 rc = 0;
2491
2492 return rc;
2493}
2494
2495int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002496CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002497{
2498 int rc = 0;
2499 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002500 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002501
2502 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2503 if (rc)
2504 return rc;
2505
2506 pSMB->FileID = (__u16) smb_file_id;
2507 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002508 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002509 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002510 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002511 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002512
2513 return rc;
2514}
2515
2516int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002517CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002518 const char *from_name, const char *to_name,
2519 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520{
2521 int rc = 0;
2522 RENAME_REQ *pSMB = NULL;
2523 RENAME_RSP *pSMBr = NULL;
2524 int bytes_returned;
2525 int name_len, name_len2;
2526 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002527 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
Joe Perchesf96637b2013-05-04 22:12:25 -05002529 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530renameRetry:
2531 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2532 (void **) &pSMBr);
2533 if (rc)
2534 return rc;
2535
2536 pSMB->BufferFormat = 0x04;
2537 pSMB->SearchAttributes =
2538 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2539 ATTR_DIRECTORY);
2540
2541 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002542 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2543 from_name, PATH_MAX,
2544 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 name_len++; /* trailing null */
2546 name_len *= 2;
2547 pSMB->OldFileName[name_len] = 0x04; /* pad */
2548 /* protocol requires ASCII signature byte on Unicode string */
2549 pSMB->OldFileName[name_len + 1] = 0x00;
2550 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002551 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002552 to_name, PATH_MAX, cifs_sb->local_nls,
2553 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2555 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002556 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002557 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002559 strncpy(pSMB->OldFileName, from_name, name_len);
2560 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 name_len2++; /* trailing null */
2562 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002563 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 name_len2++; /* trailing null */
2565 name_len2++; /* signature byte */
2566 }
2567
2568 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002569 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 pSMB->ByteCount = cpu_to_le16(count);
2571
2572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2573 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002574 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002575 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002576 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 cifs_buf_release(pSMB);
2579
2580 if (rc == -EAGAIN)
2581 goto renameRetry;
2582
2583 return rc;
2584}
2585
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002586int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002587 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002588 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589{
2590 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2591 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002592 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 char *data_offset;
2594 char dummy_string[30];
2595 int rc = 0;
2596 int bytes_returned = 0;
2597 int len_of_str;
2598 __u16 params, param_offset, offset, count, byte_count;
2599
Joe Perchesf96637b2013-05-04 22:12:25 -05002600 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2602 (void **) &pSMBr);
2603 if (rc)
2604 return rc;
2605
2606 params = 6;
2607 pSMB->MaxSetupCount = 0;
2608 pSMB->Reserved = 0;
2609 pSMB->Flags = 0;
2610 pSMB->Timeout = 0;
2611 pSMB->Reserved2 = 0;
2612 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2613 offset = param_offset + params;
2614
2615 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2616 rename_info = (struct set_file_rename *) data_offset;
2617 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002618 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 pSMB->SetupCount = 1;
2620 pSMB->Reserved3 = 0;
2621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2622 byte_count = 3 /* pad */ + params;
2623 pSMB->ParameterCount = cpu_to_le16(params);
2624 pSMB->TotalParameterCount = pSMB->ParameterCount;
2625 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2626 pSMB->DataOffset = cpu_to_le16(offset);
2627 /* construct random name ".cifs_tmp<inodenum><mid>" */
2628 rename_info->overwrite = cpu_to_le32(1);
2629 rename_info->root_fid = 0;
2630 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002631 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002632 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002633 len_of_str =
2634 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002635 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002637 len_of_str =
2638 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002639 target_name, PATH_MAX, nls_codepage,
2640 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 }
2642 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002643 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 byte_count += count;
2645 pSMB->DataCount = cpu_to_le16(count);
2646 pSMB->TotalDataCount = pSMB->DataCount;
2647 pSMB->Fid = netfid;
2648 pSMB->InformationLevel =
2649 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2650 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002651 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 pSMB->ByteCount = cpu_to_le16(byte_count);
2653 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002654 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002655 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002656 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002657 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2658 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 cifs_buf_release(pSMB);
2661
2662 /* Note: On -EAGAIN error only caller can retry on handle based calls
2663 since file handle passed in no longer valid */
2664
2665 return rc;
2666}
2667
2668int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002669CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2670 const char *fromName, const __u16 target_tid, const char *toName,
2671 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672{
2673 int rc = 0;
2674 COPY_REQ *pSMB = NULL;
2675 COPY_RSP *pSMBr = NULL;
2676 int bytes_returned;
2677 int name_len, name_len2;
2678 __u16 count;
2679
Joe Perchesf96637b2013-05-04 22:12:25 -05002680 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681copyRetry:
2682 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2683 (void **) &pSMBr);
2684 if (rc)
2685 return rc;
2686
2687 pSMB->BufferFormat = 0x04;
2688 pSMB->Tid2 = target_tid;
2689
2690 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2691
2692 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002693 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2694 fromName, PATH_MAX, nls_codepage,
2695 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 name_len++; /* trailing null */
2697 name_len *= 2;
2698 pSMB->OldFileName[name_len] = 0x04; /* pad */
2699 /* protocol requires ASCII signature byte on Unicode string */
2700 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002701 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002702 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2703 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2705 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002706 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 name_len = strnlen(fromName, PATH_MAX);
2708 name_len++; /* trailing null */
2709 strncpy(pSMB->OldFileName, fromName, name_len);
2710 name_len2 = strnlen(toName, PATH_MAX);
2711 name_len2++; /* trailing null */
2712 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2713 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2714 name_len2++; /* trailing null */
2715 name_len2++; /* signature byte */
2716 }
2717
2718 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002719 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 pSMB->ByteCount = cpu_to_le16(count);
2721
2722 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2723 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2724 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002725 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2726 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 }
Steve French0d817bc2008-05-22 02:02:03 +00002728 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
2730 if (rc == -EAGAIN)
2731 goto copyRetry;
2732
2733 return rc;
2734}
2735
2736int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002737CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 const char *fromName, const char *toName,
2739 const struct nls_table *nls_codepage)
2740{
2741 TRANSACTION2_SPI_REQ *pSMB = NULL;
2742 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2743 char *data_offset;
2744 int name_len;
2745 int name_len_target;
2746 int rc = 0;
2747 int bytes_returned = 0;
2748 __u16 params, param_offset, offset, byte_count;
2749
Joe Perchesf96637b2013-05-04 22:12:25 -05002750 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751createSymLinkRetry:
2752 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2753 (void **) &pSMBr);
2754 if (rc)
2755 return rc;
2756
2757 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2758 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002759 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2760 /* find define for this maxpathcomponent */
2761 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 name_len++; /* trailing null */
2763 name_len *= 2;
2764
Steve French50c2f752007-07-13 00:33:32 +00002765 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 name_len = strnlen(fromName, PATH_MAX);
2767 name_len++; /* trailing null */
2768 strncpy(pSMB->FileName, fromName, name_len);
2769 }
2770 params = 6 + name_len;
2771 pSMB->MaxSetupCount = 0;
2772 pSMB->Reserved = 0;
2773 pSMB->Flags = 0;
2774 pSMB->Timeout = 0;
2775 pSMB->Reserved2 = 0;
2776 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002777 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 offset = param_offset + params;
2779
2780 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2782 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002783 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2784 /* find define for this maxpathcomponent */
2785 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 name_len_target++; /* trailing null */
2787 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002788 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 name_len_target = strnlen(toName, PATH_MAX);
2790 name_len_target++; /* trailing null */
2791 strncpy(data_offset, toName, name_len_target);
2792 }
2793
2794 pSMB->MaxParameterCount = cpu_to_le16(2);
2795 /* BB find exact max on data count below from sess */
2796 pSMB->MaxDataCount = cpu_to_le16(1000);
2797 pSMB->SetupCount = 1;
2798 pSMB->Reserved3 = 0;
2799 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2800 byte_count = 3 /* pad */ + params + name_len_target;
2801 pSMB->DataCount = cpu_to_le16(name_len_target);
2802 pSMB->ParameterCount = cpu_to_le16(params);
2803 pSMB->TotalDataCount = pSMB->DataCount;
2804 pSMB->TotalParameterCount = pSMB->ParameterCount;
2805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2806 pSMB->DataOffset = cpu_to_le16(offset);
2807 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2808 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002809 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 pSMB->ByteCount = cpu_to_le16(byte_count);
2811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002813 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002814 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002815 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2816 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817
Steve French0d817bc2008-05-22 02:02:03 +00002818 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819
2820 if (rc == -EAGAIN)
2821 goto createSymLinkRetry;
2822
2823 return rc;
2824}
2825
2826int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002827CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002829 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830{
2831 TRANSACTION2_SPI_REQ *pSMB = NULL;
2832 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2833 char *data_offset;
2834 int name_len;
2835 int name_len_target;
2836 int rc = 0;
2837 int bytes_returned = 0;
2838 __u16 params, param_offset, offset, byte_count;
2839
Joe Perchesf96637b2013-05-04 22:12:25 -05002840 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841createHardLinkRetry:
2842 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2843 (void **) &pSMBr);
2844 if (rc)
2845 return rc;
2846
2847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002848 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2849 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 name_len++; /* trailing null */
2851 name_len *= 2;
2852
Steve French50c2f752007-07-13 00:33:32 +00002853 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 name_len = strnlen(toName, PATH_MAX);
2855 name_len++; /* trailing null */
2856 strncpy(pSMB->FileName, toName, name_len);
2857 }
2858 params = 6 + name_len;
2859 pSMB->MaxSetupCount = 0;
2860 pSMB->Reserved = 0;
2861 pSMB->Flags = 0;
2862 pSMB->Timeout = 0;
2863 pSMB->Reserved2 = 0;
2864 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002865 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 offset = param_offset + params;
2867
2868 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2869 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2870 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002871 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2872 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 name_len_target++; /* trailing null */
2874 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002875 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 name_len_target = strnlen(fromName, PATH_MAX);
2877 name_len_target++; /* trailing null */
2878 strncpy(data_offset, fromName, name_len_target);
2879 }
2880
2881 pSMB->MaxParameterCount = cpu_to_le16(2);
2882 /* BB find exact max on data count below from sess*/
2883 pSMB->MaxDataCount = cpu_to_le16(1000);
2884 pSMB->SetupCount = 1;
2885 pSMB->Reserved3 = 0;
2886 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2887 byte_count = 3 /* pad */ + params + name_len_target;
2888 pSMB->ParameterCount = cpu_to_le16(params);
2889 pSMB->TotalParameterCount = pSMB->ParameterCount;
2890 pSMB->DataCount = cpu_to_le16(name_len_target);
2891 pSMB->TotalDataCount = pSMB->DataCount;
2892 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2893 pSMB->DataOffset = cpu_to_le16(offset);
2894 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2895 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002896 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 pSMB->ByteCount = cpu_to_le16(byte_count);
2898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002900 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002901 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002902 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2903 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
2905 cifs_buf_release(pSMB);
2906 if (rc == -EAGAIN)
2907 goto createHardLinkRetry;
2908
2909 return rc;
2910}
2911
2912int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002913CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002914 const char *from_name, const char *to_name,
2915 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916{
2917 int rc = 0;
2918 NT_RENAME_REQ *pSMB = NULL;
2919 RENAME_RSP *pSMBr = NULL;
2920 int bytes_returned;
2921 int name_len, name_len2;
2922 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002923 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
Joe Perchesf96637b2013-05-04 22:12:25 -05002925 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926winCreateHardLinkRetry:
2927
2928 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2929 (void **) &pSMBr);
2930 if (rc)
2931 return rc;
2932
2933 pSMB->SearchAttributes =
2934 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2935 ATTR_DIRECTORY);
2936 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2937 pSMB->ClusterCount = 0;
2938
2939 pSMB->BufferFormat = 0x04;
2940
2941 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2942 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002943 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2944 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 name_len++; /* trailing null */
2946 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002947
2948 /* protocol specifies ASCII buffer format (0x04) for unicode */
2949 pSMB->OldFileName[name_len] = 0x04;
2950 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002952 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002953 to_name, PATH_MAX, cifs_sb->local_nls,
2954 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2956 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002957 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002958 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002960 strncpy(pSMB->OldFileName, from_name, name_len);
2961 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 name_len2++; /* trailing null */
2963 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002964 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 name_len2++; /* trailing null */
2966 name_len2++; /* signature byte */
2967 }
2968
2969 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002970 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 pSMB->ByteCount = cpu_to_le16(count);
2972
2973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002975 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002976 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002977 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002978
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 cifs_buf_release(pSMB);
2980 if (rc == -EAGAIN)
2981 goto winCreateHardLinkRetry;
2982
2983 return rc;
2984}
2985
2986int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002987CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002988 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 const struct nls_table *nls_codepage)
2990{
2991/* SMB_QUERY_FILE_UNIX_LINK */
2992 TRANSACTION2_QPI_REQ *pSMB = NULL;
2993 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2994 int rc = 0;
2995 int bytes_returned;
2996 int name_len;
2997 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002998 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999
Joe Perchesf96637b2013-05-04 22:12:25 -05003000 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
3002querySymLinkRetry:
3003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3004 (void **) &pSMBr);
3005 if (rc)
3006 return rc;
3007
3008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3009 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003010 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3011 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 name_len++; /* trailing null */
3013 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003014 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 name_len = strnlen(searchName, PATH_MAX);
3016 name_len++; /* trailing null */
3017 strncpy(pSMB->FileName, searchName, name_len);
3018 }
3019
3020 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3021 pSMB->TotalDataCount = 0;
3022 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003023 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 pSMB->MaxSetupCount = 0;
3025 pSMB->Reserved = 0;
3026 pSMB->Flags = 0;
3027 pSMB->Timeout = 0;
3028 pSMB->Reserved2 = 0;
3029 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003030 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 pSMB->DataCount = 0;
3032 pSMB->DataOffset = 0;
3033 pSMB->SetupCount = 1;
3034 pSMB->Reserved3 = 0;
3035 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3036 byte_count = params + 1 /* pad */ ;
3037 pSMB->TotalParameterCount = cpu_to_le16(params);
3038 pSMB->ParameterCount = pSMB->TotalParameterCount;
3039 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3040 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003041 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 pSMB->ByteCount = cpu_to_le16(byte_count);
3043
3044 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3045 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3046 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003047 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 } else {
3049 /* decode response */
3050
3051 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003053 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003054 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003056 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003057 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
Jeff Layton460b9692009-04-30 07:17:56 -04003059 data_start = ((char *) &pSMBr->hdr.Protocol) +
3060 le16_to_cpu(pSMBr->t2.DataOffset);
3061
Steve French0e0d2cf2009-05-01 05:27:32 +00003062 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3063 is_unicode = true;
3064 else
3065 is_unicode = false;
3066
Steve French737b7582005-04-28 22:41:06 -07003067 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003068 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3069 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003070 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003071 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 }
3073 }
3074 cifs_buf_release(pSMB);
3075 if (rc == -EAGAIN)
3076 goto querySymLinkRetry;
3077 return rc;
3078}
3079
Steve Frenchc52a9552011-02-24 06:16:22 +00003080#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3081/*
3082 * Recent Windows versions now create symlinks more frequently
3083 * and they use the "reparse point" mechanism below. We can of course
3084 * do symlinks nicely to Samba and other servers which support the
3085 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3086 * "MF" symlinks optionally, but for recent Windows we really need to
3087 * reenable the code below and fix the cifs_symlink callers to handle this.
3088 * In the interim this code has been moved to its own config option so
3089 * it is not compiled in by default until callers fixed up and more tested.
3090 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003092CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003094 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 const struct nls_table *nls_codepage)
3096{
3097 int rc = 0;
3098 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003099 struct smb_com_transaction_ioctl_req *pSMB;
3100 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101
Joe Perchesf96637b2013-05-04 22:12:25 -05003102 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3103 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3105 (void **) &pSMBr);
3106 if (rc)
3107 return rc;
3108
3109 pSMB->TotalParameterCount = 0 ;
3110 pSMB->TotalDataCount = 0;
3111 pSMB->MaxParameterCount = cpu_to_le32(2);
3112 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003113 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 pSMB->MaxSetupCount = 4;
3115 pSMB->Reserved = 0;
3116 pSMB->ParameterOffset = 0;
3117 pSMB->DataCount = 0;
3118 pSMB->DataOffset = 0;
3119 pSMB->SetupCount = 4;
3120 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3121 pSMB->ParameterCount = pSMB->TotalParameterCount;
3122 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3123 pSMB->IsFsctl = 1; /* FSCTL */
3124 pSMB->IsRootFlag = 0;
3125 pSMB->Fid = fid; /* file handle always le */
3126 pSMB->ByteCount = 0;
3127
3128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3130 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003131 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 } else { /* decode response */
3133 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3134 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003135 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3136 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003138 goto qreparse_out;
3139 }
3140 if (data_count && (data_count < 2048)) {
3141 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003142 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
Steve Frenchafe48c32009-05-02 05:25:46 +00003144 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003145 (struct reparse_data *)
3146 ((char *)&pSMBr->hdr.Protocol
3147 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003148 if ((char *)reparse_buf >= end_of_smb) {
3149 rc = -EIO;
3150 goto qreparse_out;
3151 }
3152 if ((reparse_buf->LinkNamesBuf +
3153 reparse_buf->TargetNameOffset +
3154 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003155 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003156 rc = -EIO;
3157 goto qreparse_out;
3158 }
Steve French50c2f752007-07-13 00:33:32 +00003159
Steve Frenchafe48c32009-05-02 05:25:46 +00003160 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3161 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003162 (reparse_buf->LinkNamesBuf +
3163 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003164 buflen,
3165 reparse_buf->TargetNameLen,
3166 nls_codepage, 0);
3167 } else { /* ASCII names */
3168 strncpy(symlinkinfo,
3169 reparse_buf->LinkNamesBuf +
3170 reparse_buf->TargetNameOffset,
3171 min_t(const int, buflen,
3172 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003174 } else {
3175 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003176 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003178 symlinkinfo[buflen] = 0; /* just in case so the caller
3179 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003180 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 }
Steve French989c7e52009-05-02 05:32:20 +00003182
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003184 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
3186 /* Note: On -EAGAIN error only caller can retry on handle based calls
3187 since file handle passed in no longer valid */
3188
3189 return rc;
3190}
Steve Frenchc52a9552011-02-24 06:16:22 +00003191#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193#ifdef CONFIG_CIFS_POSIX
3194
3195/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003196static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3197 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198{
3199 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003200 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3201 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3202 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003203/*
3204 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3205 ace->e_perm, ace->e_tag, ace->e_id);
3206*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
3208 return;
3209}
3210
3211/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003212static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3213 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214{
3215 int size = 0;
3216 int i;
3217 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003218 struct cifs_posix_ace *pACE;
3219 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3220 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3223 return -EOPNOTSUPP;
3224
Steve French790fe572007-07-07 19:25:05 +00003225 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 count = le16_to_cpu(cifs_acl->access_entry_count);
3227 pACE = &cifs_acl->ace_array[0];
3228 size = sizeof(struct cifs_posix_acl);
3229 size += sizeof(struct cifs_posix_ace) * count;
3230 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003231 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003232 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3233 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 return -EINVAL;
3235 }
Steve French790fe572007-07-07 19:25:05 +00003236 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 count = le16_to_cpu(cifs_acl->access_entry_count);
3238 size = sizeof(struct cifs_posix_acl);
3239 size += sizeof(struct cifs_posix_ace) * count;
3240/* skip past access ACEs to get to default ACEs */
3241 pACE = &cifs_acl->ace_array[count];
3242 count = le16_to_cpu(cifs_acl->default_entry_count);
3243 size += sizeof(struct cifs_posix_ace) * count;
3244 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003245 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 return -EINVAL;
3247 } else {
3248 /* illegal type */
3249 return -EINVAL;
3250 }
3251
3252 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003253 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003254 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003255 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 return -ERANGE;
3257 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003258 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003259 for (i = 0; i < count ; i++) {
3260 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3261 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 }
3263 }
3264 return size;
3265}
3266
Steve French50c2f752007-07-13 00:33:32 +00003267static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3268 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269{
3270 __u16 rc = 0; /* 0 = ACL converted ok */
3271
Steve Frenchff7feac2005-11-15 16:45:16 -08003272 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3273 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003275 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 /* Probably no need to le convert -1 on any arch but can not hurt */
3277 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003278 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003279 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003280/*
3281 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3282 ace->e_perm, ace->e_tag, ace->e_id);
3283*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 return rc;
3285}
3286
3287/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003288static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3289 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290{
3291 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003292 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3293 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 int count;
3295 int i;
3296
Steve French790fe572007-07-07 19:25:05 +00003297 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 return 0;
3299
3300 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003301 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3302 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003303 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003304 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3305 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 return 0;
3307 }
3308 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003309 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003310 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003311 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003312 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003314 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 return 0;
3316 }
Steve French50c2f752007-07-13 00:33:32 +00003317 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3319 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003320 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 /* ACE not converted */
3322 break;
3323 }
3324 }
Steve French790fe572007-07-07 19:25:05 +00003325 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3327 rc += sizeof(struct cifs_posix_acl);
3328 /* BB add check to make sure ACL does not overflow SMB */
3329 }
3330 return rc;
3331}
3332
3333int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003334CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003335 const unsigned char *searchName,
3336 char *acl_inf, const int buflen, const int acl_type,
3337 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338{
3339/* SMB_QUERY_POSIX_ACL */
3340 TRANSACTION2_QPI_REQ *pSMB = NULL;
3341 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3342 int rc = 0;
3343 int bytes_returned;
3344 int name_len;
3345 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003346
Joe Perchesf96637b2013-05-04 22:12:25 -05003347 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
3349queryAclRetry:
3350 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3351 (void **) &pSMBr);
3352 if (rc)
3353 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003354
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3356 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003357 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3358 searchName, PATH_MAX, nls_codepage,
3359 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 name_len++; /* trailing null */
3361 name_len *= 2;
3362 pSMB->FileName[name_len] = 0;
3363 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003364 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 name_len = strnlen(searchName, PATH_MAX);
3366 name_len++; /* trailing null */
3367 strncpy(pSMB->FileName, searchName, name_len);
3368 }
3369
3370 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3371 pSMB->TotalDataCount = 0;
3372 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003373 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 pSMB->MaxDataCount = cpu_to_le16(4000);
3375 pSMB->MaxSetupCount = 0;
3376 pSMB->Reserved = 0;
3377 pSMB->Flags = 0;
3378 pSMB->Timeout = 0;
3379 pSMB->Reserved2 = 0;
3380 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003381 offsetof(struct smb_com_transaction2_qpi_req,
3382 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 pSMB->DataCount = 0;
3384 pSMB->DataOffset = 0;
3385 pSMB->SetupCount = 1;
3386 pSMB->Reserved3 = 0;
3387 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3388 byte_count = params + 1 /* pad */ ;
3389 pSMB->TotalParameterCount = cpu_to_le16(params);
3390 pSMB->ParameterCount = pSMB->TotalParameterCount;
3391 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3392 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003393 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 pSMB->ByteCount = cpu_to_le16(byte_count);
3395
3396 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3397 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003398 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003400 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 } else {
3402 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003403
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003406 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 rc = -EIO; /* bad smb */
3408 else {
3409 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3410 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3411 rc = cifs_copy_posix_acl(acl_inf,
3412 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003413 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 }
3415 }
3416 cifs_buf_release(pSMB);
3417 if (rc == -EAGAIN)
3418 goto queryAclRetry;
3419 return rc;
3420}
3421
3422int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003423CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003424 const unsigned char *fileName,
3425 const char *local_acl, const int buflen,
3426 const int acl_type,
3427 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428{
3429 struct smb_com_transaction2_spi_req *pSMB = NULL;
3430 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3431 char *parm_data;
3432 int name_len;
3433 int rc = 0;
3434 int bytes_returned = 0;
3435 __u16 params, byte_count, data_count, param_offset, offset;
3436
Joe Perchesf96637b2013-05-04 22:12:25 -05003437 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438setAclRetry:
3439 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003440 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 if (rc)
3442 return rc;
3443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3444 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003445 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3446 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 name_len++; /* trailing null */
3448 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003449 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 name_len = strnlen(fileName, PATH_MAX);
3451 name_len++; /* trailing null */
3452 strncpy(pSMB->FileName, fileName, name_len);
3453 }
3454 params = 6 + name_len;
3455 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003456 /* BB find max SMB size from sess */
3457 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 pSMB->MaxSetupCount = 0;
3459 pSMB->Reserved = 0;
3460 pSMB->Flags = 0;
3461 pSMB->Timeout = 0;
3462 pSMB->Reserved2 = 0;
3463 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003464 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 offset = param_offset + params;
3466 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3467 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3468
3469 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003470 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
Steve French790fe572007-07-07 19:25:05 +00003472 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 rc = -EOPNOTSUPP;
3474 goto setACLerrorExit;
3475 }
3476 pSMB->DataOffset = cpu_to_le16(offset);
3477 pSMB->SetupCount = 1;
3478 pSMB->Reserved3 = 0;
3479 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3480 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3481 byte_count = 3 /* pad */ + params + data_count;
3482 pSMB->DataCount = cpu_to_le16(data_count);
3483 pSMB->TotalDataCount = pSMB->DataCount;
3484 pSMB->ParameterCount = cpu_to_le16(params);
3485 pSMB->TotalParameterCount = pSMB->ParameterCount;
3486 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003487 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 pSMB->ByteCount = cpu_to_le16(byte_count);
3489 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003490 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003491 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003492 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
3494setACLerrorExit:
3495 cifs_buf_release(pSMB);
3496 if (rc == -EAGAIN)
3497 goto setAclRetry;
3498 return rc;
3499}
3500
Steve Frenchf654bac2005-04-28 22:41:04 -07003501/* BB fix tabs in this function FIXME BB */
3502int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003503CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003504 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003505{
Steve French50c2f752007-07-13 00:33:32 +00003506 int rc = 0;
3507 struct smb_t2_qfi_req *pSMB = NULL;
3508 struct smb_t2_qfi_rsp *pSMBr = NULL;
3509 int bytes_returned;
3510 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003511
Joe Perchesf96637b2013-05-04 22:12:25 -05003512 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003513 if (tcon == NULL)
3514 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003515
3516GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003517 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3518 (void **) &pSMBr);
3519 if (rc)
3520 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003521
Steve Frenchad7a2922008-02-07 23:25:02 +00003522 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003523 pSMB->t2.TotalDataCount = 0;
3524 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3525 /* BB find exact max data count below from sess structure BB */
3526 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3527 pSMB->t2.MaxSetupCount = 0;
3528 pSMB->t2.Reserved = 0;
3529 pSMB->t2.Flags = 0;
3530 pSMB->t2.Timeout = 0;
3531 pSMB->t2.Reserved2 = 0;
3532 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3533 Fid) - 4);
3534 pSMB->t2.DataCount = 0;
3535 pSMB->t2.DataOffset = 0;
3536 pSMB->t2.SetupCount = 1;
3537 pSMB->t2.Reserved3 = 0;
3538 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3539 byte_count = params + 1 /* pad */ ;
3540 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3541 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3542 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3543 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003544 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003545 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003546 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003547
Steve French790fe572007-07-07 19:25:05 +00003548 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3549 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3550 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003551 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003552 } else {
3553 /* decode response */
3554 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003555 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003556 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003557 /* If rc should we check for EOPNOSUPP and
3558 disable the srvino flag? or in caller? */
3559 rc = -EIO; /* bad smb */
3560 else {
3561 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3562 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3563 struct file_chattr_info *pfinfo;
3564 /* BB Do we need a cast or hash here ? */
3565 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003566 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003567 rc = -EIO;
3568 goto GetExtAttrOut;
3569 }
3570 pfinfo = (struct file_chattr_info *)
3571 (data_offset + (char *) &pSMBr->hdr.Protocol);
3572 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003573 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003574 }
3575 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003576GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003577 cifs_buf_release(pSMB);
3578 if (rc == -EAGAIN)
3579 goto GetExtAttrRetry;
3580 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003581}
3582
Steve Frenchf654bac2005-04-28 22:41:04 -07003583#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
Jeff Layton79df1ba2010-12-06 12:52:08 -05003585#ifdef CONFIG_CIFS_ACL
3586/*
3587 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3588 * all NT TRANSACTS that we init here have total parm and data under about 400
3589 * bytes (to fit in small cifs buffer size), which is the case so far, it
3590 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3591 * returned setup area) and MaxParameterCount (returned parms size) must be set
3592 * by caller
3593 */
3594static int
3595smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003596 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003597 void **ret_buf)
3598{
3599 int rc;
3600 __u32 temp_offset;
3601 struct smb_com_ntransact_req *pSMB;
3602
3603 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3604 (void **)&pSMB);
3605 if (rc)
3606 return rc;
3607 *ret_buf = (void *)pSMB;
3608 pSMB->Reserved = 0;
3609 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3610 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003611 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003612 pSMB->ParameterCount = pSMB->TotalParameterCount;
3613 pSMB->DataCount = pSMB->TotalDataCount;
3614 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3615 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3616 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3617 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3618 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3619 pSMB->SubCommand = cpu_to_le16(sub_command);
3620 return 0;
3621}
3622
3623static int
3624validate_ntransact(char *buf, char **ppparm, char **ppdata,
3625 __u32 *pparmlen, __u32 *pdatalen)
3626{
3627 char *end_of_smb;
3628 __u32 data_count, data_offset, parm_count, parm_offset;
3629 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003630 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003631
3632 *pdatalen = 0;
3633 *pparmlen = 0;
3634
3635 if (buf == NULL)
3636 return -EINVAL;
3637
3638 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3639
Jeff Layton820a8032011-05-04 08:05:26 -04003640 bcc = get_bcc(&pSMBr->hdr);
3641 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003642 (char *)&pSMBr->ByteCount;
3643
3644 data_offset = le32_to_cpu(pSMBr->DataOffset);
3645 data_count = le32_to_cpu(pSMBr->DataCount);
3646 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3647 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3648
3649 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3650 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3651
3652 /* should we also check that parm and data areas do not overlap? */
3653 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003654 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003655 return -EINVAL;
3656 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003657 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003658 return -EINVAL;
3659 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003660 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003661 return -EINVAL;
3662 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003663 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3664 *ppdata, data_count, (data_count + *ppdata),
3665 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003666 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003667 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003668 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003669 return -EINVAL;
3670 }
3671 *pdatalen = data_count;
3672 *pparmlen = parm_count;
3673 return 0;
3674}
3675
Steve French0a4b92c2006-01-12 15:44:21 -08003676/* Get Security Descriptor (by handle) from remote server for a file or dir */
3677int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003678CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003679 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003680{
3681 int rc = 0;
3682 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003683 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003684 struct kvec iov[1];
3685
Joe Perchesf96637b2013-05-04 22:12:25 -05003686 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003687
Steve French630f3f0c2007-10-25 21:17:17 +00003688 *pbuflen = 0;
3689 *acl_inf = NULL;
3690
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003691 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003692 8 /* parm len */, tcon, (void **) &pSMB);
3693 if (rc)
3694 return rc;
3695
3696 pSMB->MaxParameterCount = cpu_to_le32(4);
3697 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3698 pSMB->MaxSetupCount = 0;
3699 pSMB->Fid = fid; /* file handle always le */
3700 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3701 CIFS_ACL_DACL);
3702 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003703 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003704 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003705 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003706
Steve Frencha761ac52007-10-18 21:45:27 +00003707 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003708 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003709 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003710 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003711 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003712 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003713 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003714 __u32 parm_len;
3715 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003716 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003717 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003718
3719/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003720 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003721 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003722 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003723 goto qsec_out;
3724 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3725
Joe Perchesf96637b2013-05-04 22:12:25 -05003726 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3727 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003728
3729 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3730 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003731 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003732 goto qsec_out;
3733 }
3734
3735/* BB check that data area is minimum length and as big as acl_len */
3736
Steve Frenchaf6f4612007-10-16 18:40:37 +00003737 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003738 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003739 cifs_dbg(VFS, "acl length %d does not match %d\n",
3740 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003741 if (*pbuflen > acl_len)
3742 *pbuflen = acl_len;
3743 }
Steve French0a4b92c2006-01-12 15:44:21 -08003744
Steve French630f3f0c2007-10-25 21:17:17 +00003745 /* check if buffer is big enough for the acl
3746 header followed by the smallest SID */
3747 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3748 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003749 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003750 rc = -EINVAL;
3751 *pbuflen = 0;
3752 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003753 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003754 if (*acl_inf == NULL) {
3755 *pbuflen = 0;
3756 rc = -ENOMEM;
3757 }
Steve French630f3f0c2007-10-25 21:17:17 +00003758 }
Steve French0a4b92c2006-01-12 15:44:21 -08003759 }
3760qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003761 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003762 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003763 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003764 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003765/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003766 return rc;
3767}
Steve French97837582007-12-31 07:47:21 +00003768
3769int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003770CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003771 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003772{
3773 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3774 int rc = 0;
3775 int bytes_returned = 0;
3776 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003777 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003778
3779setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003780 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003781 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003782 return rc;
Steve French97837582007-12-31 07:47:21 +00003783
3784 pSMB->MaxSetupCount = 0;
3785 pSMB->Reserved = 0;
3786
3787 param_count = 8;
3788 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3789 data_count = acllen;
3790 data_offset = param_offset + param_count;
3791 byte_count = 3 /* pad */ + param_count;
3792
3793 pSMB->DataCount = cpu_to_le32(data_count);
3794 pSMB->TotalDataCount = pSMB->DataCount;
3795 pSMB->MaxParameterCount = cpu_to_le32(4);
3796 pSMB->MaxDataCount = cpu_to_le32(16384);
3797 pSMB->ParameterCount = cpu_to_le32(param_count);
3798 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3799 pSMB->TotalParameterCount = pSMB->ParameterCount;
3800 pSMB->DataOffset = cpu_to_le32(data_offset);
3801 pSMB->SetupCount = 0;
3802 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3803 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3804
3805 pSMB->Fid = fid; /* file handle always le */
3806 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003807 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003808
3809 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003810 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3811 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003812 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003813 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003814 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003815
3816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3818
Joe Perchesf96637b2013-05-04 22:12:25 -05003819 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3820 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003821 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003822 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003823 cifs_buf_release(pSMB);
3824
3825 if (rc == -EAGAIN)
3826 goto setCifsAclRetry;
3827
3828 return (rc);
3829}
3830
Jeff Layton79df1ba2010-12-06 12:52:08 -05003831#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003832
Steve French6b8edfe2005-08-23 20:26:03 -07003833/* Legacy Query Path Information call for lookup to old servers such
3834 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003835int
3836SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3837 const char *search_name, FILE_ALL_INFO *data,
3838 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003839{
Steve Frenchad7a2922008-02-07 23:25:02 +00003840 QUERY_INFORMATION_REQ *pSMB;
3841 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003842 int rc = 0;
3843 int bytes_returned;
3844 int name_len;
3845
Joe Perchesf96637b2013-05-04 22:12:25 -05003846 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003847QInfRetry:
3848 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003849 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003850 if (rc)
3851 return rc;
3852
3853 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3854 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003855 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003856 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003857 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003858 name_len++; /* trailing null */
3859 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003860 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003861 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003862 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003863 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003864 }
3865 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003866 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003867 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003868 pSMB->ByteCount = cpu_to_le16(name_len);
3869
3870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003872 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003873 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003874 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003875 struct timespec ts;
3876 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003877
3878 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003879 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003880 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003881 ts.tv_nsec = 0;
3882 ts.tv_sec = time;
3883 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003884 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3885 data->LastWriteTime = data->ChangeTime;
3886 data->LastAccessTime = 0;
3887 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003888 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003889 data->EndOfFile = data->AllocationSize;
3890 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003891 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003892 } else
3893 rc = -EIO; /* bad buffer passed in */
3894
3895 cifs_buf_release(pSMB);
3896
3897 if (rc == -EAGAIN)
3898 goto QInfRetry;
3899
3900 return rc;
3901}
3902
Jeff Laytonbcd53572010-02-12 07:44:16 -05003903int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003904CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003905 u16 netfid, FILE_ALL_INFO *pFindData)
3906{
3907 struct smb_t2_qfi_req *pSMB = NULL;
3908 struct smb_t2_qfi_rsp *pSMBr = NULL;
3909 int rc = 0;
3910 int bytes_returned;
3911 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003912
Jeff Laytonbcd53572010-02-12 07:44:16 -05003913QFileInfoRetry:
3914 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3915 (void **) &pSMBr);
3916 if (rc)
3917 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003918
Jeff Laytonbcd53572010-02-12 07:44:16 -05003919 params = 2 /* level */ + 2 /* fid */;
3920 pSMB->t2.TotalDataCount = 0;
3921 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3922 /* BB find exact max data count below from sess structure BB */
3923 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3924 pSMB->t2.MaxSetupCount = 0;
3925 pSMB->t2.Reserved = 0;
3926 pSMB->t2.Flags = 0;
3927 pSMB->t2.Timeout = 0;
3928 pSMB->t2.Reserved2 = 0;
3929 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3930 Fid) - 4);
3931 pSMB->t2.DataCount = 0;
3932 pSMB->t2.DataOffset = 0;
3933 pSMB->t2.SetupCount = 1;
3934 pSMB->t2.Reserved3 = 0;
3935 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3936 byte_count = params + 1 /* pad */ ;
3937 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3938 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3939 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3940 pSMB->Pad = 0;
3941 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003942 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003943
3944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3946 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003947 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003948 } else { /* decode response */
3949 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3950
3951 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3952 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003953 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003954 rc = -EIO; /* bad smb */
3955 else if (pFindData) {
3956 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3957 memcpy((char *) pFindData,
3958 (char *) &pSMBr->hdr.Protocol +
3959 data_offset, sizeof(FILE_ALL_INFO));
3960 } else
3961 rc = -ENOMEM;
3962 }
3963 cifs_buf_release(pSMB);
3964 if (rc == -EAGAIN)
3965 goto QFileInfoRetry;
3966
3967 return rc;
3968}
Steve French6b8edfe2005-08-23 20:26:03 -07003969
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003971CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003972 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003973 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003974 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003976 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 TRANSACTION2_QPI_REQ *pSMB = NULL;
3978 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3979 int rc = 0;
3980 int bytes_returned;
3981 int name_len;
3982 __u16 params, byte_count;
3983
Joe Perchesf96637b2013-05-04 22:12:25 -05003984 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985QPathInfoRetry:
3986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3987 (void **) &pSMBr);
3988 if (rc)
3989 return rc;
3990
3991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3992 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003993 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003994 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 name_len++; /* trailing null */
3996 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003997 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003998 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004000 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 }
4002
Steve French50c2f752007-07-13 00:33:32 +00004003 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 pSMB->TotalDataCount = 0;
4005 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004006 /* BB find exact max SMB PDU from sess structure BB */
4007 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 pSMB->MaxSetupCount = 0;
4009 pSMB->Reserved = 0;
4010 pSMB->Flags = 0;
4011 pSMB->Timeout = 0;
4012 pSMB->Reserved2 = 0;
4013 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004014 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 pSMB->DataCount = 0;
4016 pSMB->DataOffset = 0;
4017 pSMB->SetupCount = 1;
4018 pSMB->Reserved3 = 0;
4019 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4020 byte_count = params + 1 /* pad */ ;
4021 pSMB->TotalParameterCount = cpu_to_le16(params);
4022 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004023 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004024 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4025 else
4026 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004028 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 pSMB->ByteCount = cpu_to_le16(byte_count);
4030
4031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4033 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004034 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 } else { /* decode response */
4036 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4037
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004038 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4039 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004040 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004042 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004043 rc = -EIO; /* 24 or 26 expected but we do not read
4044 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004045 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004046 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004048
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004049 /*
4050 * On legacy responses we do not read the last field,
4051 * EAsize, fortunately since it varies by subdialect and
4052 * also note it differs on Set vs Get, ie two bytes or 4
4053 * bytes depending but we don't care here.
4054 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004055 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004056 size = sizeof(FILE_INFO_STANDARD);
4057 else
4058 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004059 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004060 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 } else
4062 rc = -ENOMEM;
4063 }
4064 cifs_buf_release(pSMB);
4065 if (rc == -EAGAIN)
4066 goto QPathInfoRetry;
4067
4068 return rc;
4069}
4070
4071int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004072CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004073 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4074{
4075 struct smb_t2_qfi_req *pSMB = NULL;
4076 struct smb_t2_qfi_rsp *pSMBr = NULL;
4077 int rc = 0;
4078 int bytes_returned;
4079 __u16 params, byte_count;
4080
4081UnixQFileInfoRetry:
4082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4083 (void **) &pSMBr);
4084 if (rc)
4085 return rc;
4086
4087 params = 2 /* level */ + 2 /* fid */;
4088 pSMB->t2.TotalDataCount = 0;
4089 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4090 /* BB find exact max data count below from sess structure BB */
4091 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4092 pSMB->t2.MaxSetupCount = 0;
4093 pSMB->t2.Reserved = 0;
4094 pSMB->t2.Flags = 0;
4095 pSMB->t2.Timeout = 0;
4096 pSMB->t2.Reserved2 = 0;
4097 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4098 Fid) - 4);
4099 pSMB->t2.DataCount = 0;
4100 pSMB->t2.DataOffset = 0;
4101 pSMB->t2.SetupCount = 1;
4102 pSMB->t2.Reserved3 = 0;
4103 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4104 byte_count = params + 1 /* pad */ ;
4105 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4106 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4107 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4108 pSMB->Pad = 0;
4109 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004110 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004111
4112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4113 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4114 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004115 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004116 } else { /* decode response */
4117 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4118
Jeff Layton820a8032011-05-04 08:05:26 -04004119 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004120 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 -05004121 rc = -EIO; /* bad smb */
4122 } else {
4123 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4124 memcpy((char *) pFindData,
4125 (char *) &pSMBr->hdr.Protocol +
4126 data_offset,
4127 sizeof(FILE_UNIX_BASIC_INFO));
4128 }
4129 }
4130
4131 cifs_buf_release(pSMB);
4132 if (rc == -EAGAIN)
4133 goto UnixQFileInfoRetry;
4134
4135 return rc;
4136}
4137
4138int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004139CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004141 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004142 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143{
4144/* SMB_QUERY_FILE_UNIX_BASIC */
4145 TRANSACTION2_QPI_REQ *pSMB = NULL;
4146 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4147 int rc = 0;
4148 int bytes_returned = 0;
4149 int name_len;
4150 __u16 params, byte_count;
4151
Joe Perchesf96637b2013-05-04 22:12:25 -05004152 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153UnixQPathInfoRetry:
4154 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4155 (void **) &pSMBr);
4156 if (rc)
4157 return rc;
4158
4159 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4160 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004161 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4162 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 name_len++; /* trailing null */
4164 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004165 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 name_len = strnlen(searchName, PATH_MAX);
4167 name_len++; /* trailing null */
4168 strncpy(pSMB->FileName, searchName, name_len);
4169 }
4170
Steve French50c2f752007-07-13 00:33:32 +00004171 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 pSMB->TotalDataCount = 0;
4173 pSMB->MaxParameterCount = cpu_to_le16(2);
4174 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004175 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 pSMB->MaxSetupCount = 0;
4177 pSMB->Reserved = 0;
4178 pSMB->Flags = 0;
4179 pSMB->Timeout = 0;
4180 pSMB->Reserved2 = 0;
4181 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004182 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 pSMB->DataCount = 0;
4184 pSMB->DataOffset = 0;
4185 pSMB->SetupCount = 1;
4186 pSMB->Reserved3 = 0;
4187 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4188 byte_count = params + 1 /* pad */ ;
4189 pSMB->TotalParameterCount = cpu_to_le16(params);
4190 pSMB->ParameterCount = pSMB->TotalParameterCount;
4191 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4192 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004193 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 pSMB->ByteCount = cpu_to_le16(byte_count);
4195
4196 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4198 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004199 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 } else { /* decode response */
4201 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4202
Jeff Layton820a8032011-05-04 08:05:26 -04004203 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004204 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 -07004205 rc = -EIO; /* bad smb */
4206 } else {
4207 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4208 memcpy((char *) pFindData,
4209 (char *) &pSMBr->hdr.Protocol +
4210 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004211 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 }
4213 }
4214 cifs_buf_release(pSMB);
4215 if (rc == -EAGAIN)
4216 goto UnixQPathInfoRetry;
4217
4218 return rc;
4219}
4220
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221/* xid, tcon, searchName and codepage are input parms, rest are returned */
4222int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004223CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004224 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004225 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004226 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227{
4228/* level 257 SMB_ */
4229 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4230 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004231 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 int rc = 0;
4233 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004234 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004236 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
Joe Perchesf96637b2013-05-04 22:12:25 -05004238 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239
4240findFirstRetry:
4241 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4242 (void **) &pSMBr);
4243 if (rc)
4244 return rc;
4245
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004246 nls_codepage = cifs_sb->local_nls;
4247 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4248
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4250 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004251 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4252 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004253 /* We can not add the asterik earlier in case
4254 it got remapped to 0xF03A as if it were part of the
4255 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004257 if (msearch) {
4258 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4259 pSMB->FileName[name_len+1] = 0;
4260 pSMB->FileName[name_len+2] = '*';
4261 pSMB->FileName[name_len+3] = 0;
4262 name_len += 4; /* now the trailing null */
4263 /* null terminate just in case */
4264 pSMB->FileName[name_len] = 0;
4265 pSMB->FileName[name_len+1] = 0;
4266 name_len += 2;
4267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 } else { /* BB add check for overrun of SMB buf BB */
4269 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004271 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 free buffer exit; BB */
4273 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004274 if (msearch) {
4275 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4276 pSMB->FileName[name_len+1] = '*';
4277 pSMB->FileName[name_len+2] = 0;
4278 name_len += 3;
4279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 }
4281
4282 params = 12 + name_len /* includes null */ ;
4283 pSMB->TotalDataCount = 0; /* no EAs */
4284 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004285 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 pSMB->MaxSetupCount = 0;
4287 pSMB->Reserved = 0;
4288 pSMB->Flags = 0;
4289 pSMB->Timeout = 0;
4290 pSMB->Reserved2 = 0;
4291 byte_count = params + 1 /* pad */ ;
4292 pSMB->TotalParameterCount = cpu_to_le16(params);
4293 pSMB->ParameterCount = pSMB->TotalParameterCount;
4294 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004295 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4296 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 pSMB->DataCount = 0;
4298 pSMB->DataOffset = 0;
4299 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4300 pSMB->Reserved3 = 0;
4301 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4302 pSMB->SearchAttributes =
4303 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4304 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004305 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004306 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4308
4309 /* BB what should we set StorageType to? Does it matter? BB */
4310 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004311 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 pSMB->ByteCount = cpu_to_le16(byte_count);
4313
4314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4315 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004316 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317
Steve French88274812006-03-09 22:21:45 +00004318 if (rc) {/* BB add logic to retry regular search if Unix search
4319 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004321 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004322
Steve French88274812006-03-09 22:21:45 +00004323 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
4325 /* BB eventually could optimize out free and realloc of buf */
4326 /* for this case */
4327 if (rc == -EAGAIN)
4328 goto findFirstRetry;
4329 } else { /* decode response */
4330 /* BB remember to free buffer if error BB */
4331 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004332 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004333 unsigned int lnoff;
4334
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004336 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 else
Steve French4b18f2a2008-04-29 00:06:05 +00004338 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
4340 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004341 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004342 psrch_inf->srch_entries_start =
4343 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4346 le16_to_cpu(pSMBr->t2.ParameterOffset));
4347
Steve French790fe572007-07-07 19:25:05 +00004348 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004349 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 else
Steve French4b18f2a2008-04-29 00:06:05 +00004351 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
Steve French50c2f752007-07-13 00:33:32 +00004353 psrch_inf->entries_in_buffer =
4354 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004355 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004357 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004358 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004359 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004360 psrch_inf->last_entry = NULL;
4361 return rc;
4362 }
4363
Steve French0752f152008-10-07 20:03:33 +00004364 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004365 lnoff;
4366
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004367 if (pnetfid)
4368 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 } else {
4370 cifs_buf_release(pSMB);
4371 }
4372 }
4373
4374 return rc;
4375}
4376
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004377int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4378 __u16 searchHandle, __u16 search_flags,
4379 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380{
4381 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4382 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004383 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 char *response_data;
4385 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004386 int bytes_returned;
4387 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 __u16 params, byte_count;
4389
Joe Perchesf96637b2013-05-04 22:12:25 -05004390 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
Steve French4b18f2a2008-04-29 00:06:05 +00004392 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 return -ENOENT;
4394
4395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4396 (void **) &pSMBr);
4397 if (rc)
4398 return rc;
4399
Steve French50c2f752007-07-13 00:33:32 +00004400 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 byte_count = 0;
4402 pSMB->TotalDataCount = 0; /* no EAs */
4403 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004404 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 pSMB->MaxSetupCount = 0;
4406 pSMB->Reserved = 0;
4407 pSMB->Flags = 0;
4408 pSMB->Timeout = 0;
4409 pSMB->Reserved2 = 0;
4410 pSMB->ParameterOffset = cpu_to_le16(
4411 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4412 pSMB->DataCount = 0;
4413 pSMB->DataOffset = 0;
4414 pSMB->SetupCount = 1;
4415 pSMB->Reserved3 = 0;
4416 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4417 pSMB->SearchHandle = searchHandle; /* always kept as le */
4418 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004419 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4421 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004422 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
4424 name_len = psrch_inf->resume_name_len;
4425 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004426 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4428 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004429 /* 14 byte parm len above enough for 2 byte null terminator */
4430 pSMB->ResumeFileName[name_len] = 0;
4431 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 } else {
4433 rc = -EINVAL;
4434 goto FNext2_err_exit;
4435 }
4436 byte_count = params + 1 /* pad */ ;
4437 pSMB->TotalParameterCount = cpu_to_le16(params);
4438 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004439 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004441
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004444 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 if (rc) {
4446 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004447 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004448 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004449 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004451 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 } else { /* decode response */
4453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004454
Steve French790fe572007-07-07 19:25:05 +00004455 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004456 unsigned int lnoff;
4457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 /* BB fixme add lock for file (srch_info) struct here */
4459 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004460 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 else
Steve French4b18f2a2008-04-29 00:06:05 +00004462 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 response_data = (char *) &pSMBr->hdr.Protocol +
4464 le16_to_cpu(pSMBr->t2.ParameterOffset);
4465 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4466 response_data = (char *)&pSMBr->hdr.Protocol +
4467 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004468 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004469 cifs_small_buf_release(
4470 psrch_inf->ntwrk_buf_start);
4471 else
4472 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 psrch_inf->srch_entries_start = response_data;
4474 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004475 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004476 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004477 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 else
Steve French4b18f2a2008-04-29 00:06:05 +00004479 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004480 psrch_inf->entries_in_buffer =
4481 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 psrch_inf->index_of_last_entry +=
4483 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004484 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004485 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004486 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004487 psrch_inf->last_entry = NULL;
4488 return rc;
4489 } else
4490 psrch_inf->last_entry =
4491 psrch_inf->srch_entries_start + lnoff;
4492
Joe Perchesf96637b2013-05-04 22:12:25 -05004493/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4494 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
4496 /* BB fixme add unlock here */
4497 }
4498
4499 }
4500
4501 /* BB On error, should we leave previous search buf (and count and
4502 last entry fields) intact or free the previous one? */
4503
4504 /* Note: On -EAGAIN error only caller can retry on handle based calls
4505 since file handle passed in no longer valid */
4506FNext2_err_exit:
4507 if (rc != 0)
4508 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 return rc;
4510}
4511
4512int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004513CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004514 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515{
4516 int rc = 0;
4517 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518
Joe Perchesf96637b2013-05-04 22:12:25 -05004519 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4521
4522 /* no sense returning error if session restarted
4523 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004524 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 return 0;
4526 if (rc)
4527 return rc;
4528
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 pSMB->FileID = searchHandle;
4530 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004531 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004532 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004533 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004534
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004535 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
4537 /* Since session is dead, search handle closed on server already */
4538 if (rc == -EAGAIN)
4539 rc = 0;
4540
4541 return rc;
4542}
4543
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004545CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004546 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004547 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548{
4549 int rc = 0;
4550 TRANSACTION2_QPI_REQ *pSMB = NULL;
4551 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4552 int name_len, bytes_returned;
4553 __u16 params, byte_count;
4554
Joe Perchesf96637b2013-05-04 22:12:25 -05004555 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004556 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004557 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
4559GetInodeNumberRetry:
4560 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004561 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 if (rc)
4563 return rc;
4564
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4566 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004567 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004568 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004569 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 name_len++; /* trailing null */
4571 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004572 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004573 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004575 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 }
4577
4578 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4579 pSMB->TotalDataCount = 0;
4580 pSMB->MaxParameterCount = cpu_to_le16(2);
4581 /* BB find exact max data count below from sess structure BB */
4582 pSMB->MaxDataCount = cpu_to_le16(4000);
4583 pSMB->MaxSetupCount = 0;
4584 pSMB->Reserved = 0;
4585 pSMB->Flags = 0;
4586 pSMB->Timeout = 0;
4587 pSMB->Reserved2 = 0;
4588 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004589 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 pSMB->DataCount = 0;
4591 pSMB->DataOffset = 0;
4592 pSMB->SetupCount = 1;
4593 pSMB->Reserved3 = 0;
4594 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4595 byte_count = params + 1 /* pad */ ;
4596 pSMB->TotalParameterCount = cpu_to_le16(params);
4597 pSMB->ParameterCount = pSMB->TotalParameterCount;
4598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4599 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004600 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 pSMB->ByteCount = cpu_to_le16(byte_count);
4602
4603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4605 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004606 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 } else {
4608 /* decode response */
4609 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004611 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 /* If rc should we check for EOPNOSUPP and
4613 disable the srvino flag? or in caller? */
4614 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004615 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4617 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004618 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004620 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004621 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 rc = -EIO;
4623 goto GetInodeNumOut;
4624 }
4625 pfinfo = (struct file_internal_info *)
4626 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004627 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 }
4629 }
4630GetInodeNumOut:
4631 cifs_buf_release(pSMB);
4632 if (rc == -EAGAIN)
4633 goto GetInodeNumberRetry;
4634 return rc;
4635}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
Igor Mammedovfec45852008-05-16 13:06:30 +04004637/* parses DFS refferal V3 structure
4638 * caller is responsible for freeing target_nodes
4639 * returns:
4640 * on success - 0
4641 * on failure - errno
4642 */
4643static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004644parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004645 unsigned int *num_of_nodes,
4646 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004647 const struct nls_table *nls_codepage, int remap,
4648 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004649{
4650 int i, rc = 0;
4651 char *data_end;
4652 bool is_unicode;
4653 struct dfs_referral_level_3 *ref;
4654
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004655 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4656 is_unicode = true;
4657 else
4658 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004659 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4660
4661 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004662 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4663 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004664 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004665 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004666 }
4667
4668 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004669 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004670 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4671 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004672 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004673 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004674 }
4675
4676 /* get the upper boundary of the resp buffer */
4677 data_end = (char *)(&(pSMBr->PathConsumed)) +
4678 le16_to_cpu(pSMBr->t2.DataCount);
4679
Joe Perchesf96637b2013-05-04 22:12:25 -05004680 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4681 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004682
Joe Perchesf96637b2013-05-04 22:12:25 -05004683 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4684 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004686 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004687 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004688 }
4689
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004690 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004691 for (i = 0; i < *num_of_nodes; i++) {
4692 char *temp;
4693 int max_len;
4694 struct dfs_info3_param *node = (*target_nodes)+i;
4695
Steve French0e0d2cf2009-05-01 05:27:32 +00004696 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004697 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004698 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4699 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004700 if (tmp == NULL) {
4701 rc = -ENOMEM;
4702 goto parse_DFS_referrals_exit;
4703 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004704 cifsConvertToUTF16((__le16 *) tmp, searchName,
4705 PATH_MAX, nls_codepage, remap);
4706 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004707 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004708 nls_codepage);
4709 kfree(tmp);
4710 } else
4711 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4712
Igor Mammedovfec45852008-05-16 13:06:30 +04004713 node->server_type = le16_to_cpu(ref->ServerType);
4714 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4715
4716 /* copy DfsPath */
4717 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4718 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004719 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4720 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004721 if (!node->path_name) {
4722 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004723 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004724 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004725
4726 /* copy link target UNC */
4727 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4728 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004729 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4730 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004731 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004732 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004733 goto parse_DFS_referrals_exit;
4734 }
4735
4736 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004737 }
4738
Steve Frencha1fe78f2008-05-16 18:48:38 +00004739parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004740 if (rc) {
4741 free_dfs_info_array(*target_nodes, *num_of_nodes);
4742 *target_nodes = NULL;
4743 *num_of_nodes = 0;
4744 }
4745 return rc;
4746}
4747
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004749CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004750 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004751 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004752 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753{
4754/* TRANS2_GET_DFS_REFERRAL */
4755 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4756 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 int rc = 0;
4758 int bytes_returned;
4759 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004761 *num_of_nodes = 0;
4762 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Joe Perchesf96637b2013-05-04 22:12:25 -05004764 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 if (ses == NULL)
4766 return -ENODEV;
4767getDFSRetry:
4768 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4769 (void **) &pSMBr);
4770 if (rc)
4771 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004772
4773 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004774 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004775 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 pSMB->hdr.Tid = ses->ipc_tid;
4777 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004778 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004780 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782
4783 if (ses->capabilities & CAP_UNICODE) {
4784 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4785 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004786 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004787 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004788 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 name_len++; /* trailing null */
4790 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004791 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004792 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004794 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 }
4796
Steve French790fe572007-07-07 19:25:05 +00004797 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004798 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004799 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4800 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4801 }
4802
Steve French50c2f752007-07-13 00:33:32 +00004803 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004804
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 params = 2 /* level */ + name_len /*includes null */ ;
4806 pSMB->TotalDataCount = 0;
4807 pSMB->DataCount = 0;
4808 pSMB->DataOffset = 0;
4809 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004810 /* BB find exact max SMB PDU from sess structure BB */
4811 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 pSMB->MaxSetupCount = 0;
4813 pSMB->Reserved = 0;
4814 pSMB->Flags = 0;
4815 pSMB->Timeout = 0;
4816 pSMB->Reserved2 = 0;
4817 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004818 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 pSMB->SetupCount = 1;
4820 pSMB->Reserved3 = 0;
4821 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4822 byte_count = params + 3 /* pad */ ;
4823 pSMB->ParameterCount = cpu_to_le16(params);
4824 pSMB->TotalParameterCount = pSMB->ParameterCount;
4825 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004826 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 pSMB->ByteCount = cpu_to_le16(byte_count);
4828
4829 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4831 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004832 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004833 goto GetDFSRefExit;
4834 }
4835 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004837 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004838 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004839 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004840 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004842
Joe Perchesf96637b2013-05-04 22:12:25 -05004843 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4844 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004845
4846 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004847 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004848 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004849 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004850
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004852 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853
4854 if (rc == -EAGAIN)
4855 goto getDFSRetry;
4856
4857 return rc;
4858}
4859
Steve French20962432005-09-21 22:05:57 -07004860/* Query File System Info such as free space to old servers such as Win 9x */
4861int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004862SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4863 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004864{
4865/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4866 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4867 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4868 FILE_SYSTEM_ALLOC_INFO *response_data;
4869 int rc = 0;
4870 int bytes_returned = 0;
4871 __u16 params, byte_count;
4872
Joe Perchesf96637b2013-05-04 22:12:25 -05004873 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004874oldQFSInfoRetry:
4875 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4876 (void **) &pSMBr);
4877 if (rc)
4878 return rc;
Steve French20962432005-09-21 22:05:57 -07004879
4880 params = 2; /* level */
4881 pSMB->TotalDataCount = 0;
4882 pSMB->MaxParameterCount = cpu_to_le16(2);
4883 pSMB->MaxDataCount = cpu_to_le16(1000);
4884 pSMB->MaxSetupCount = 0;
4885 pSMB->Reserved = 0;
4886 pSMB->Flags = 0;
4887 pSMB->Timeout = 0;
4888 pSMB->Reserved2 = 0;
4889 byte_count = params + 1 /* pad */ ;
4890 pSMB->TotalParameterCount = cpu_to_le16(params);
4891 pSMB->ParameterCount = pSMB->TotalParameterCount;
4892 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4893 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4894 pSMB->DataCount = 0;
4895 pSMB->DataOffset = 0;
4896 pSMB->SetupCount = 1;
4897 pSMB->Reserved3 = 0;
4898 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4899 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004900 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004901 pSMB->ByteCount = cpu_to_le16(byte_count);
4902
4903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4905 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004906 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004907 } else { /* decode response */
4908 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4909
Jeff Layton820a8032011-05-04 08:05:26 -04004910 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004911 rc = -EIO; /* bad smb */
4912 else {
4913 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004914 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004915 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004916
Steve French50c2f752007-07-13 00:33:32 +00004917 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004918 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4919 FSData->f_bsize =
4920 le16_to_cpu(response_data->BytesPerSector) *
4921 le32_to_cpu(response_data->
4922 SectorsPerAllocationUnit);
4923 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004924 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004925 FSData->f_bfree = FSData->f_bavail =
4926 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004927 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4928 (unsigned long long)FSData->f_blocks,
4929 (unsigned long long)FSData->f_bfree,
4930 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004931 }
4932 }
4933 cifs_buf_release(pSMB);
4934
4935 if (rc == -EAGAIN)
4936 goto oldQFSInfoRetry;
4937
4938 return rc;
4939}
4940
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004942CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4943 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944{
4945/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4946 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4947 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4948 FILE_SYSTEM_INFO *response_data;
4949 int rc = 0;
4950 int bytes_returned = 0;
4951 __u16 params, byte_count;
4952
Joe Perchesf96637b2013-05-04 22:12:25 -05004953 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954QFSInfoRetry:
4955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4956 (void **) &pSMBr);
4957 if (rc)
4958 return rc;
4959
4960 params = 2; /* level */
4961 pSMB->TotalDataCount = 0;
4962 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004963 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 pSMB->MaxSetupCount = 0;
4965 pSMB->Reserved = 0;
4966 pSMB->Flags = 0;
4967 pSMB->Timeout = 0;
4968 pSMB->Reserved2 = 0;
4969 byte_count = params + 1 /* pad */ ;
4970 pSMB->TotalParameterCount = cpu_to_le16(params);
4971 pSMB->ParameterCount = pSMB->TotalParameterCount;
4972 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004973 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 pSMB->DataCount = 0;
4975 pSMB->DataOffset = 0;
4976 pSMB->SetupCount = 1;
4977 pSMB->Reserved3 = 0;
4978 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4979 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004980 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 pSMB->ByteCount = cpu_to_le16(byte_count);
4982
4983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4985 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004986 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004988 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989
Jeff Layton820a8032011-05-04 08:05:26 -04004990 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 rc = -EIO; /* bad smb */
4992 else {
4993 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994
4995 response_data =
4996 (FILE_SYSTEM_INFO
4997 *) (((char *) &pSMBr->hdr.Protocol) +
4998 data_offset);
4999 FSData->f_bsize =
5000 le32_to_cpu(response_data->BytesPerSector) *
5001 le32_to_cpu(response_data->
5002 SectorsPerAllocationUnit);
5003 FSData->f_blocks =
5004 le64_to_cpu(response_data->TotalAllocationUnits);
5005 FSData->f_bfree = FSData->f_bavail =
5006 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005007 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5008 (unsigned long long)FSData->f_blocks,
5009 (unsigned long long)FSData->f_bfree,
5010 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 }
5012 }
5013 cifs_buf_release(pSMB);
5014
5015 if (rc == -EAGAIN)
5016 goto QFSInfoRetry;
5017
5018 return rc;
5019}
5020
5021int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005022CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023{
5024/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5025 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5026 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5027 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5028 int rc = 0;
5029 int bytes_returned = 0;
5030 __u16 params, byte_count;
5031
Joe Perchesf96637b2013-05-04 22:12:25 -05005032 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033QFSAttributeRetry:
5034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5035 (void **) &pSMBr);
5036 if (rc)
5037 return rc;
5038
5039 params = 2; /* level */
5040 pSMB->TotalDataCount = 0;
5041 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005042 /* BB find exact max SMB PDU from sess structure BB */
5043 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 pSMB->MaxSetupCount = 0;
5045 pSMB->Reserved = 0;
5046 pSMB->Flags = 0;
5047 pSMB->Timeout = 0;
5048 pSMB->Reserved2 = 0;
5049 byte_count = params + 1 /* pad */ ;
5050 pSMB->TotalParameterCount = cpu_to_le16(params);
5051 pSMB->ParameterCount = pSMB->TotalParameterCount;
5052 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005053 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 pSMB->DataCount = 0;
5055 pSMB->DataOffset = 0;
5056 pSMB->SetupCount = 1;
5057 pSMB->Reserved3 = 0;
5058 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5059 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005060 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 pSMB->ByteCount = cpu_to_le16(byte_count);
5062
5063 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5064 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5065 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005066 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 } else { /* decode response */
5068 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5069
Jeff Layton820a8032011-05-04 08:05:26 -04005070 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005071 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 rc = -EIO; /* bad smb */
5073 } else {
5074 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5075 response_data =
5076 (FILE_SYSTEM_ATTRIBUTE_INFO
5077 *) (((char *) &pSMBr->hdr.Protocol) +
5078 data_offset);
5079 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005080 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 }
5082 }
5083 cifs_buf_release(pSMB);
5084
5085 if (rc == -EAGAIN)
5086 goto QFSAttributeRetry;
5087
5088 return rc;
5089}
5090
5091int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005092CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093{
5094/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5095 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5096 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5097 FILE_SYSTEM_DEVICE_INFO *response_data;
5098 int rc = 0;
5099 int bytes_returned = 0;
5100 __u16 params, byte_count;
5101
Joe Perchesf96637b2013-05-04 22:12:25 -05005102 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103QFSDeviceRetry:
5104 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5105 (void **) &pSMBr);
5106 if (rc)
5107 return rc;
5108
5109 params = 2; /* level */
5110 pSMB->TotalDataCount = 0;
5111 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005112 /* BB find exact max SMB PDU from sess structure BB */
5113 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 pSMB->MaxSetupCount = 0;
5115 pSMB->Reserved = 0;
5116 pSMB->Flags = 0;
5117 pSMB->Timeout = 0;
5118 pSMB->Reserved2 = 0;
5119 byte_count = params + 1 /* pad */ ;
5120 pSMB->TotalParameterCount = cpu_to_le16(params);
5121 pSMB->ParameterCount = pSMB->TotalParameterCount;
5122 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005123 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124
5125 pSMB->DataCount = 0;
5126 pSMB->DataOffset = 0;
5127 pSMB->SetupCount = 1;
5128 pSMB->Reserved3 = 0;
5129 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5130 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005131 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 pSMB->ByteCount = cpu_to_le16(byte_count);
5133
5134 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5135 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5136 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005137 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 } else { /* decode response */
5139 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5140
Jeff Layton820a8032011-05-04 08:05:26 -04005141 if (rc || get_bcc(&pSMBr->hdr) <
5142 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 rc = -EIO; /* bad smb */
5144 else {
5145 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5146 response_data =
Steve French737b7582005-04-28 22:41:06 -07005147 (FILE_SYSTEM_DEVICE_INFO *)
5148 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 data_offset);
5150 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005151 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 }
5153 }
5154 cifs_buf_release(pSMB);
5155
5156 if (rc == -EAGAIN)
5157 goto QFSDeviceRetry;
5158
5159 return rc;
5160}
5161
5162int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005163CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164{
5165/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5166 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5167 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5168 FILE_SYSTEM_UNIX_INFO *response_data;
5169 int rc = 0;
5170 int bytes_returned = 0;
5171 __u16 params, byte_count;
5172
Joe Perchesf96637b2013-05-04 22:12:25 -05005173 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005175 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5176 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 if (rc)
5178 return rc;
5179
5180 params = 2; /* level */
5181 pSMB->TotalDataCount = 0;
5182 pSMB->DataCount = 0;
5183 pSMB->DataOffset = 0;
5184 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005185 /* BB find exact max SMB PDU from sess structure BB */
5186 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 pSMB->MaxSetupCount = 0;
5188 pSMB->Reserved = 0;
5189 pSMB->Flags = 0;
5190 pSMB->Timeout = 0;
5191 pSMB->Reserved2 = 0;
5192 byte_count = params + 1 /* pad */ ;
5193 pSMB->ParameterCount = cpu_to_le16(params);
5194 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005195 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5196 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 pSMB->SetupCount = 1;
5198 pSMB->Reserved3 = 0;
5199 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5200 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005201 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 pSMB->ByteCount = cpu_to_le16(byte_count);
5203
5204 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5205 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5206 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005207 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 } else { /* decode response */
5209 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5210
Jeff Layton820a8032011-05-04 08:05:26 -04005211 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 rc = -EIO; /* bad smb */
5213 } else {
5214 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5215 response_data =
5216 (FILE_SYSTEM_UNIX_INFO
5217 *) (((char *) &pSMBr->hdr.Protocol) +
5218 data_offset);
5219 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005220 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 }
5222 }
5223 cifs_buf_release(pSMB);
5224
5225 if (rc == -EAGAIN)
5226 goto QFSUnixRetry;
5227
5228
5229 return rc;
5230}
5231
Jeremy Allisonac670552005-06-22 17:26:35 -07005232int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005233CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005234{
5235/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5236 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5237 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5238 int rc = 0;
5239 int bytes_returned = 0;
5240 __u16 params, param_offset, offset, byte_count;
5241
Joe Perchesf96637b2013-05-04 22:12:25 -05005242 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005243SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005244 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005245 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5246 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005247 if (rc)
5248 return rc;
5249
5250 params = 4; /* 2 bytes zero followed by info level. */
5251 pSMB->MaxSetupCount = 0;
5252 pSMB->Reserved = 0;
5253 pSMB->Flags = 0;
5254 pSMB->Timeout = 0;
5255 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005256 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5257 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005258 offset = param_offset + params;
5259
5260 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005261 /* BB find exact max SMB PDU from sess structure BB */
5262 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005263 pSMB->SetupCount = 1;
5264 pSMB->Reserved3 = 0;
5265 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5266 byte_count = 1 /* pad */ + params + 12;
5267
5268 pSMB->DataCount = cpu_to_le16(12);
5269 pSMB->ParameterCount = cpu_to_le16(params);
5270 pSMB->TotalDataCount = pSMB->DataCount;
5271 pSMB->TotalParameterCount = pSMB->ParameterCount;
5272 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5273 pSMB->DataOffset = cpu_to_le16(offset);
5274
5275 /* Params. */
5276 pSMB->FileNum = 0;
5277 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5278
5279 /* Data. */
5280 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5281 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5282 pSMB->ClientUnixCap = cpu_to_le64(cap);
5283
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005284 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005285 pSMB->ByteCount = cpu_to_le16(byte_count);
5286
5287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5288 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5289 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005290 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005291 } else { /* decode response */
5292 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005293 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005294 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005295 }
5296 cifs_buf_release(pSMB);
5297
5298 if (rc == -EAGAIN)
5299 goto SETFSUnixRetry;
5300
5301 return rc;
5302}
5303
5304
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
5306int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005307CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005308 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309{
5310/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5311 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5312 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5313 FILE_SYSTEM_POSIX_INFO *response_data;
5314 int rc = 0;
5315 int bytes_returned = 0;
5316 __u16 params, byte_count;
5317
Joe Perchesf96637b2013-05-04 22:12:25 -05005318 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319QFSPosixRetry:
5320 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5321 (void **) &pSMBr);
5322 if (rc)
5323 return rc;
5324
5325 params = 2; /* level */
5326 pSMB->TotalDataCount = 0;
5327 pSMB->DataCount = 0;
5328 pSMB->DataOffset = 0;
5329 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005330 /* BB find exact max SMB PDU from sess structure BB */
5331 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 pSMB->MaxSetupCount = 0;
5333 pSMB->Reserved = 0;
5334 pSMB->Flags = 0;
5335 pSMB->Timeout = 0;
5336 pSMB->Reserved2 = 0;
5337 byte_count = params + 1 /* pad */ ;
5338 pSMB->ParameterCount = cpu_to_le16(params);
5339 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005340 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5341 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 pSMB->SetupCount = 1;
5343 pSMB->Reserved3 = 0;
5344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005346 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 pSMB->ByteCount = cpu_to_le16(byte_count);
5348
5349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5351 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005352 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 } else { /* decode response */
5354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5355
Jeff Layton820a8032011-05-04 08:05:26 -04005356 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 rc = -EIO; /* bad smb */
5358 } else {
5359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5360 response_data =
5361 (FILE_SYSTEM_POSIX_INFO
5362 *) (((char *) &pSMBr->hdr.Protocol) +
5363 data_offset);
5364 FSData->f_bsize =
5365 le32_to_cpu(response_data->BlockSize);
5366 FSData->f_blocks =
5367 le64_to_cpu(response_data->TotalBlocks);
5368 FSData->f_bfree =
5369 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005370 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 FSData->f_bavail = FSData->f_bfree;
5372 } else {
5373 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005374 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 }
Steve French790fe572007-07-07 19:25:05 +00005376 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005378 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005379 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005381 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 }
5383 }
5384 cifs_buf_release(pSMB);
5385
5386 if (rc == -EAGAIN)
5387 goto QFSPosixRetry;
5388
5389 return rc;
5390}
5391
5392
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005393/*
5394 * We can not use write of zero bytes trick to set file size due to need for
5395 * large file support. Also note that this SetPathInfo is preferred to
5396 * SetFileInfo based method in next routine which is only needed to work around
5397 * a sharing violation bugin Samba which this routine can run into.
5398 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005400CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005401 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5402 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403{
5404 struct smb_com_transaction2_spi_req *pSMB = NULL;
5405 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5406 struct file_end_of_file_info *parm_data;
5407 int name_len;
5408 int rc = 0;
5409 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005410 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5411
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 __u16 params, byte_count, data_count, param_offset, offset;
5413
Joe Perchesf96637b2013-05-04 22:12:25 -05005414 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415SetEOFRetry:
5416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5417 (void **) &pSMBr);
5418 if (rc)
5419 return rc;
5420
5421 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5422 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005423 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5424 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 name_len++; /* trailing null */
5426 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005427 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005428 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005430 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 }
5432 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005433 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005435 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 pSMB->MaxSetupCount = 0;
5437 pSMB->Reserved = 0;
5438 pSMB->Flags = 0;
5439 pSMB->Timeout = 0;
5440 pSMB->Reserved2 = 0;
5441 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005442 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005444 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005445 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5446 pSMB->InformationLevel =
5447 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5448 else
5449 pSMB->InformationLevel =
5450 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5451 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5453 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005454 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 else
5456 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005457 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 }
5459
5460 parm_data =
5461 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5462 offset);
5463 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5464 pSMB->DataOffset = cpu_to_le16(offset);
5465 pSMB->SetupCount = 1;
5466 pSMB->Reserved3 = 0;
5467 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5468 byte_count = 3 /* pad */ + params + data_count;
5469 pSMB->DataCount = cpu_to_le16(data_count);
5470 pSMB->TotalDataCount = pSMB->DataCount;
5471 pSMB->ParameterCount = cpu_to_le16(params);
5472 pSMB->TotalParameterCount = pSMB->ParameterCount;
5473 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005474 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 parm_data->FileSize = cpu_to_le64(size);
5476 pSMB->ByteCount = cpu_to_le16(byte_count);
5477 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005479 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005480 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481
5482 cifs_buf_release(pSMB);
5483
5484 if (rc == -EAGAIN)
5485 goto SetEOFRetry;
5486
5487 return rc;
5488}
5489
5490int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005491CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5492 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493{
5494 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 struct file_end_of_file_info *parm_data;
5496 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 __u16 params, param_offset, offset, byte_count, count;
5498
Joe Perchesf96637b2013-05-04 22:12:25 -05005499 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5500 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005501 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5502
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 if (rc)
5504 return rc;
5505
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005506 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5507 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005508
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 params = 6;
5510 pSMB->MaxSetupCount = 0;
5511 pSMB->Reserved = 0;
5512 pSMB->Flags = 0;
5513 pSMB->Timeout = 0;
5514 pSMB->Reserved2 = 0;
5515 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5516 offset = param_offset + params;
5517
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 count = sizeof(struct file_end_of_file_info);
5519 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005520 /* BB find exact max SMB PDU from sess structure BB */
5521 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 pSMB->SetupCount = 1;
5523 pSMB->Reserved3 = 0;
5524 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5525 byte_count = 3 /* pad */ + params + count;
5526 pSMB->DataCount = cpu_to_le16(count);
5527 pSMB->ParameterCount = cpu_to_le16(params);
5528 pSMB->TotalDataCount = pSMB->DataCount;
5529 pSMB->TotalParameterCount = pSMB->ParameterCount;
5530 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5531 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005532 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5533 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 pSMB->DataOffset = cpu_to_le16(offset);
5535 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005536 pSMB->Fid = cfile->fid.netfid;
5537 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5539 pSMB->InformationLevel =
5540 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5541 else
5542 pSMB->InformationLevel =
5543 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005544 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5546 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005547 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 else
5549 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005550 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 }
5552 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005553 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005555 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005557 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5558 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 }
5560
Steve French50c2f752007-07-13 00:33:32 +00005561 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 since file handle passed in no longer valid */
5563
5564 return rc;
5565}
5566
Steve French50c2f752007-07-13 00:33:32 +00005567/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 an open handle, rather than by pathname - this is awkward due to
5569 potential access conflicts on the open, but it is unavoidable for these
5570 old servers since the only other choice is to go from 100 nanosecond DCE
5571 time and resort to the original setpathinfo level which takes the ancient
5572 DOS time format with 2 second granularity */
5573int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005574CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005575 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576{
5577 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 char *data_offset;
5579 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 __u16 params, param_offset, offset, byte_count, count;
5581
Joe Perchesf96637b2013-05-04 22:12:25 -05005582 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005583 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5584
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 if (rc)
5586 return rc;
5587
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005588 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5589 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005590
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 params = 6;
5592 pSMB->MaxSetupCount = 0;
5593 pSMB->Reserved = 0;
5594 pSMB->Flags = 0;
5595 pSMB->Timeout = 0;
5596 pSMB->Reserved2 = 0;
5597 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5598 offset = param_offset + params;
5599
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005600 data_offset = (char *)pSMB +
5601 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602
Steve French26f57362007-08-30 22:09:15 +00005603 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005605 /* BB find max SMB PDU from sess */
5606 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 pSMB->SetupCount = 1;
5608 pSMB->Reserved3 = 0;
5609 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5610 byte_count = 3 /* pad */ + params + count;
5611 pSMB->DataCount = cpu_to_le16(count);
5612 pSMB->ParameterCount = cpu_to_le16(params);
5613 pSMB->TotalDataCount = pSMB->DataCount;
5614 pSMB->TotalParameterCount = pSMB->ParameterCount;
5615 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5616 pSMB->DataOffset = cpu_to_le16(offset);
5617 pSMB->Fid = fid;
5618 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5619 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5620 else
5621 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5622 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005623 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005625 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005626 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005627 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005628 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5629 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630
Steve French50c2f752007-07-13 00:33:32 +00005631 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 since file handle passed in no longer valid */
5633
5634 return rc;
5635}
5636
Jeff Layton6d22f092008-09-23 11:48:35 -04005637int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005638CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005639 bool delete_file, __u16 fid, __u32 pid_of_opener)
5640{
5641 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5642 char *data_offset;
5643 int rc = 0;
5644 __u16 params, param_offset, offset, byte_count, count;
5645
Joe Perchesf96637b2013-05-04 22:12:25 -05005646 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005647 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5648
5649 if (rc)
5650 return rc;
5651
5652 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5653 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5654
5655 params = 6;
5656 pSMB->MaxSetupCount = 0;
5657 pSMB->Reserved = 0;
5658 pSMB->Flags = 0;
5659 pSMB->Timeout = 0;
5660 pSMB->Reserved2 = 0;
5661 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5662 offset = param_offset + params;
5663
5664 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5665
5666 count = 1;
5667 pSMB->MaxParameterCount = cpu_to_le16(2);
5668 /* BB find max SMB PDU from sess */
5669 pSMB->MaxDataCount = cpu_to_le16(1000);
5670 pSMB->SetupCount = 1;
5671 pSMB->Reserved3 = 0;
5672 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5673 byte_count = 3 /* pad */ + params + count;
5674 pSMB->DataCount = cpu_to_le16(count);
5675 pSMB->ParameterCount = cpu_to_le16(params);
5676 pSMB->TotalDataCount = pSMB->DataCount;
5677 pSMB->TotalParameterCount = pSMB->ParameterCount;
5678 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5679 pSMB->DataOffset = cpu_to_le16(offset);
5680 pSMB->Fid = fid;
5681 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5682 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005683 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005684 pSMB->ByteCount = cpu_to_le16(byte_count);
5685 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005686 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005687 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005688 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005689
5690 return rc;
5691}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
5693int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005694CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005695 const char *fileName, const FILE_BASIC_INFO *data,
5696 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697{
5698 TRANSACTION2_SPI_REQ *pSMB = NULL;
5699 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5700 int name_len;
5701 int rc = 0;
5702 int bytes_returned = 0;
5703 char *data_offset;
5704 __u16 params, param_offset, offset, byte_count, count;
5705
Joe Perchesf96637b2013-05-04 22:12:25 -05005706 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
5708SetTimesRetry:
5709 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5710 (void **) &pSMBr);
5711 if (rc)
5712 return rc;
5713
5714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5715 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005716 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5717 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 name_len++; /* trailing null */
5719 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005720 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 name_len = strnlen(fileName, PATH_MAX);
5722 name_len++; /* trailing null */
5723 strncpy(pSMB->FileName, fileName, name_len);
5724 }
5725
5726 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005727 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005729 /* BB find max SMB PDU from sess structure BB */
5730 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 pSMB->MaxSetupCount = 0;
5732 pSMB->Reserved = 0;
5733 pSMB->Flags = 0;
5734 pSMB->Timeout = 0;
5735 pSMB->Reserved2 = 0;
5736 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005737 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 offset = param_offset + params;
5739 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5740 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5741 pSMB->DataOffset = cpu_to_le16(offset);
5742 pSMB->SetupCount = 1;
5743 pSMB->Reserved3 = 0;
5744 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5745 byte_count = 3 /* pad */ + params + count;
5746
5747 pSMB->DataCount = cpu_to_le16(count);
5748 pSMB->ParameterCount = cpu_to_le16(params);
5749 pSMB->TotalDataCount = pSMB->DataCount;
5750 pSMB->TotalParameterCount = pSMB->ParameterCount;
5751 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5752 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5753 else
5754 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5755 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005756 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005757 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 pSMB->ByteCount = cpu_to_le16(byte_count);
5759 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005761 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005762 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763
5764 cifs_buf_release(pSMB);
5765
5766 if (rc == -EAGAIN)
5767 goto SetTimesRetry;
5768
5769 return rc;
5770}
5771
5772/* Can not be used to set time stamps yet (due to old DOS time format) */
5773/* Can be used to set attributes */
5774#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5775 handling it anyway and NT4 was what we thought it would be needed for
5776 Do not delete it until we prove whether needed for Win9x though */
5777int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005778CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 __u16 dos_attrs, const struct nls_table *nls_codepage)
5780{
5781 SETATTR_REQ *pSMB = NULL;
5782 SETATTR_RSP *pSMBr = NULL;
5783 int rc = 0;
5784 int bytes_returned;
5785 int name_len;
5786
Joe Perchesf96637b2013-05-04 22:12:25 -05005787 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788
5789SetAttrLgcyRetry:
5790 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5791 (void **) &pSMBr);
5792 if (rc)
5793 return rc;
5794
5795 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5796 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005797 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5798 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799 name_len++; /* trailing null */
5800 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005801 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 name_len = strnlen(fileName, PATH_MAX);
5803 name_len++; /* trailing null */
5804 strncpy(pSMB->fileName, fileName, name_len);
5805 }
5806 pSMB->attr = cpu_to_le16(dos_attrs);
5807 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005808 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5810 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005812 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005813 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814
5815 cifs_buf_release(pSMB);
5816
5817 if (rc == -EAGAIN)
5818 goto SetAttrLgcyRetry;
5819
5820 return rc;
5821}
5822#endif /* temporarily unneeded SetAttr legacy function */
5823
Jeff Layton654cf142009-07-09 20:02:49 -04005824static void
5825cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5826 const struct cifs_unix_set_info_args *args)
5827{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005828 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005829 u64 mode = args->mode;
5830
Eric W. Biederman49418b22013-02-06 00:57:56 -08005831 if (uid_valid(args->uid))
5832 uid = from_kuid(&init_user_ns, args->uid);
5833 if (gid_valid(args->gid))
5834 gid = from_kgid(&init_user_ns, args->gid);
5835
Jeff Layton654cf142009-07-09 20:02:49 -04005836 /*
5837 * Samba server ignores set of file size to zero due to bugs in some
5838 * older clients, but we should be precise - we use SetFileSize to
5839 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005840 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005841 * zero instead of -1 here
5842 */
5843 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5844 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5845 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5846 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5847 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005848 data_offset->Uid = cpu_to_le64(uid);
5849 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005850 /* better to leave device as zero when it is */
5851 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5852 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5853 data_offset->Permissions = cpu_to_le64(mode);
5854
5855 if (S_ISREG(mode))
5856 data_offset->Type = cpu_to_le32(UNIX_FILE);
5857 else if (S_ISDIR(mode))
5858 data_offset->Type = cpu_to_le32(UNIX_DIR);
5859 else if (S_ISLNK(mode))
5860 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5861 else if (S_ISCHR(mode))
5862 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5863 else if (S_ISBLK(mode))
5864 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5865 else if (S_ISFIFO(mode))
5866 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5867 else if (S_ISSOCK(mode))
5868 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5869}
5870
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005872CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005873 const struct cifs_unix_set_info_args *args,
5874 u16 fid, u32 pid_of_opener)
5875{
5876 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005877 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005878 int rc = 0;
5879 u16 params, param_offset, offset, byte_count, count;
5880
Joe Perchesf96637b2013-05-04 22:12:25 -05005881 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005882 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5883
5884 if (rc)
5885 return rc;
5886
5887 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5888 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5889
5890 params = 6;
5891 pSMB->MaxSetupCount = 0;
5892 pSMB->Reserved = 0;
5893 pSMB->Flags = 0;
5894 pSMB->Timeout = 0;
5895 pSMB->Reserved2 = 0;
5896 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5897 offset = param_offset + params;
5898
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005899 data_offset = (char *)pSMB +
5900 offsetof(struct smb_hdr, Protocol) + offset;
5901
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005902 count = sizeof(FILE_UNIX_BASIC_INFO);
5903
5904 pSMB->MaxParameterCount = cpu_to_le16(2);
5905 /* BB find max SMB PDU from sess */
5906 pSMB->MaxDataCount = cpu_to_le16(1000);
5907 pSMB->SetupCount = 1;
5908 pSMB->Reserved3 = 0;
5909 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5910 byte_count = 3 /* pad */ + params + count;
5911 pSMB->DataCount = cpu_to_le16(count);
5912 pSMB->ParameterCount = cpu_to_le16(params);
5913 pSMB->TotalDataCount = pSMB->DataCount;
5914 pSMB->TotalParameterCount = pSMB->ParameterCount;
5915 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5916 pSMB->DataOffset = cpu_to_le16(offset);
5917 pSMB->Fid = fid;
5918 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5919 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005920 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005921 pSMB->ByteCount = cpu_to_le16(byte_count);
5922
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005923 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005924
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005925 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005926 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005927 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5928 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005929
5930 /* Note: On -EAGAIN error only caller can retry on handle based calls
5931 since file handle passed in no longer valid */
5932
5933 return rc;
5934}
5935
5936int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005937CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005938 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005939 const struct cifs_unix_set_info_args *args,
5940 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941{
5942 TRANSACTION2_SPI_REQ *pSMB = NULL;
5943 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5944 int name_len;
5945 int rc = 0;
5946 int bytes_returned = 0;
5947 FILE_UNIX_BASIC_INFO *data_offset;
5948 __u16 params, param_offset, offset, count, byte_count;
5949
Joe Perchesf96637b2013-05-04 22:12:25 -05005950 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951setPermsRetry:
5952 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5953 (void **) &pSMBr);
5954 if (rc)
5955 return rc;
5956
5957 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5958 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005959 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005960 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 name_len++; /* trailing null */
5962 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005963 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005964 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005966 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 }
5968
5969 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005970 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005972 /* BB find max SMB PDU from sess structure BB */
5973 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974 pSMB->MaxSetupCount = 0;
5975 pSMB->Reserved = 0;
5976 pSMB->Flags = 0;
5977 pSMB->Timeout = 0;
5978 pSMB->Reserved2 = 0;
5979 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005980 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 offset = param_offset + params;
5982 data_offset =
5983 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5984 offset);
5985 memset(data_offset, 0, count);
5986 pSMB->DataOffset = cpu_to_le16(offset);
5987 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5988 pSMB->SetupCount = 1;
5989 pSMB->Reserved3 = 0;
5990 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5991 byte_count = 3 /* pad */ + params + count;
5992 pSMB->ParameterCount = cpu_to_le16(params);
5993 pSMB->DataCount = cpu_to_le16(count);
5994 pSMB->TotalParameterCount = pSMB->ParameterCount;
5995 pSMB->TotalDataCount = pSMB->DataCount;
5996 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5997 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005998 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005999
Jeff Layton654cf142009-07-09 20:02:49 -04006000 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001
6002 pSMB->ByteCount = cpu_to_le16(byte_count);
6003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006005 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006006 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007
Steve French0d817bc2008-05-22 02:02:03 +00006008 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009 if (rc == -EAGAIN)
6010 goto setPermsRetry;
6011 return rc;
6012}
6013
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006015/*
6016 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6017 * function used by listxattr and getxattr type calls. When ea_name is set,
6018 * it looks for that attribute name and stuffs that value into the EAData
6019 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6020 * buffer. In both cases, the return value is either the length of the
6021 * resulting data or a negative error code. If EAData is a NULL pointer then
6022 * the data isn't copied to it, but the length is returned.
6023 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006025CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006026 const unsigned char *searchName, const unsigned char *ea_name,
6027 char *EAData, size_t buf_size,
6028 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029{
6030 /* BB assumes one setup word */
6031 TRANSACTION2_QPI_REQ *pSMB = NULL;
6032 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6033 int rc = 0;
6034 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006035 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006036 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006037 struct fea *temp_fea;
6038 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006039 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006040 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006041 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042
Joe Perchesf96637b2013-05-04 22:12:25 -05006043 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044QAllEAsRetry:
6045 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6046 (void **) &pSMBr);
6047 if (rc)
6048 return rc;
6049
6050 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006051 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006052 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6053 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006054 list_len++; /* trailing null */
6055 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006057 list_len = strnlen(searchName, PATH_MAX);
6058 list_len++; /* trailing null */
6059 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 }
6061
Jeff Layton6e462b92010-02-10 16:18:26 -05006062 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 pSMB->TotalDataCount = 0;
6064 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006065 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006066 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 pSMB->MaxSetupCount = 0;
6068 pSMB->Reserved = 0;
6069 pSMB->Flags = 0;
6070 pSMB->Timeout = 0;
6071 pSMB->Reserved2 = 0;
6072 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006073 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 pSMB->DataCount = 0;
6075 pSMB->DataOffset = 0;
6076 pSMB->SetupCount = 1;
6077 pSMB->Reserved3 = 0;
6078 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6079 byte_count = params + 1 /* pad */ ;
6080 pSMB->TotalParameterCount = cpu_to_le16(params);
6081 pSMB->ParameterCount = pSMB->TotalParameterCount;
6082 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6083 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006084 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 pSMB->ByteCount = cpu_to_le16(byte_count);
6086
6087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6088 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6089 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006090 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006091 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006093
6094
6095 /* BB also check enough total bytes returned */
6096 /* BB we need to improve the validity checking
6097 of these trans2 responses */
6098
6099 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006100 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006101 rc = -EIO; /* bad smb */
6102 goto QAllEAsOut;
6103 }
6104
6105 /* check that length of list is not more than bcc */
6106 /* check that each entry does not go beyond length
6107 of list */
6108 /* check that each element of each entry does not
6109 go beyond end of list */
6110 /* validate_trans2_offsets() */
6111 /* BB check if start of smb + data_offset > &bcc+ bcc */
6112
6113 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6114 ea_response_data = (struct fealist *)
6115 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6116
Jeff Layton6e462b92010-02-10 16:18:26 -05006117 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006118 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006119 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006120 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006121 goto QAllEAsOut;
6122 }
6123
Jeff Layton0cd126b2010-02-10 16:18:26 -05006124 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006125 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006126 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006127 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006128 rc = -EIO;
6129 goto QAllEAsOut;
6130 }
6131
Jeff Laytonf0d38682010-02-10 16:18:26 -05006132 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006133 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006134 temp_fea = ea_response_data->list;
6135 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006136 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006137 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006138 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006139
Jeff Layton6e462b92010-02-10 16:18:26 -05006140 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006141 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006142 /* make sure we can read name_len and value_len */
6143 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006144 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006145 rc = -EIO;
6146 goto QAllEAsOut;
6147 }
6148
6149 name_len = temp_fea->name_len;
6150 value_len = le16_to_cpu(temp_fea->value_len);
6151 list_len -= name_len + 1 + value_len;
6152 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006153 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006154 rc = -EIO;
6155 goto QAllEAsOut;
6156 }
6157
Jeff Layton31c05192010-02-10 16:18:26 -05006158 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006159 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006160 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006161 temp_ptr += name_len + 1;
6162 rc = value_len;
6163 if (buf_size == 0)
6164 goto QAllEAsOut;
6165 if ((size_t)value_len > buf_size) {
6166 rc = -ERANGE;
6167 goto QAllEAsOut;
6168 }
6169 memcpy(EAData, temp_ptr, value_len);
6170 goto QAllEAsOut;
6171 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006172 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006173 /* account for prefix user. and trailing null */
6174 rc += (5 + 1 + name_len);
6175 if (rc < (int) buf_size) {
6176 memcpy(EAData, "user.", 5);
6177 EAData += 5;
6178 memcpy(EAData, temp_ptr, name_len);
6179 EAData += name_len;
6180 /* null terminate name */
6181 *EAData = 0;
6182 ++EAData;
6183 } else if (buf_size == 0) {
6184 /* skip copy - calc size only */
6185 } else {
6186 /* stop before overrun buffer */
6187 rc = -ERANGE;
6188 break;
6189 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006190 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006191 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006192 temp_fea = (struct fea *)temp_ptr;
6193 }
6194
Jeff Layton31c05192010-02-10 16:18:26 -05006195 /* didn't find the named attribute */
6196 if (ea_name)
6197 rc = -ENODATA;
6198
Jeff Laytonf0d38682010-02-10 16:18:26 -05006199QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006200 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 if (rc == -EAGAIN)
6202 goto QAllEAsRetry;
6203
6204 return (ssize_t)rc;
6205}
6206
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006208CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6209 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006210 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6211 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212{
6213 struct smb_com_transaction2_spi_req *pSMB = NULL;
6214 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6215 struct fealist *parm_data;
6216 int name_len;
6217 int rc = 0;
6218 int bytes_returned = 0;
6219 __u16 params, param_offset, byte_count, offset, count;
6220
Joe Perchesf96637b2013-05-04 22:12:25 -05006221 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222SetEARetry:
6223 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6224 (void **) &pSMBr);
6225 if (rc)
6226 return rc;
6227
6228 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6229 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006230 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6231 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 name_len++; /* trailing null */
6233 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006234 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235 name_len = strnlen(fileName, PATH_MAX);
6236 name_len++; /* trailing null */
6237 strncpy(pSMB->FileName, fileName, name_len);
6238 }
6239
6240 params = 6 + name_len;
6241
6242 /* done calculating parms using name_len of file name,
6243 now use name_len to calculate length of ea name
6244 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006245 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 name_len = 0;
6247 else
Steve French50c2f752007-07-13 00:33:32 +00006248 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006250 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006252 /* BB find max SMB PDU from sess */
6253 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 pSMB->MaxSetupCount = 0;
6255 pSMB->Reserved = 0;
6256 pSMB->Flags = 0;
6257 pSMB->Timeout = 0;
6258 pSMB->Reserved2 = 0;
6259 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006260 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 offset = param_offset + params;
6262 pSMB->InformationLevel =
6263 cpu_to_le16(SMB_SET_FILE_EA);
6264
6265 parm_data =
6266 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6267 offset);
6268 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6269 pSMB->DataOffset = cpu_to_le16(offset);
6270 pSMB->SetupCount = 1;
6271 pSMB->Reserved3 = 0;
6272 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6273 byte_count = 3 /* pad */ + params + count;
6274 pSMB->DataCount = cpu_to_le16(count);
6275 parm_data->list_len = cpu_to_le32(count);
6276 parm_data->list[0].EA_flags = 0;
6277 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006278 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006280 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006281 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 parm_data->list[0].name[name_len] = 0;
6283 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6284 /* caller ensures that ea_value_len is less than 64K but
6285 we need to ensure that it fits within the smb */
6286
Steve French50c2f752007-07-13 00:33:32 +00006287 /*BB add length check to see if it would fit in
6288 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006289 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6290 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006291 memcpy(parm_data->list[0].name+name_len+1,
6292 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293
6294 pSMB->TotalDataCount = pSMB->DataCount;
6295 pSMB->ParameterCount = cpu_to_le16(params);
6296 pSMB->TotalParameterCount = pSMB->ParameterCount;
6297 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006298 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006299 pSMB->ByteCount = cpu_to_le16(byte_count);
6300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006302 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006303 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304
6305 cifs_buf_release(pSMB);
6306
6307 if (rc == -EAGAIN)
6308 goto SetEARetry;
6309
6310 return rc;
6311}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312#endif
Steve French0eff0e22011-02-24 05:39:23 +00006313
6314#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6315/*
6316 * Years ago the kernel added a "dnotify" function for Samba server,
6317 * to allow network clients (such as Windows) to display updated
6318 * lists of files in directory listings automatically when
6319 * files are added by one user when another user has the
6320 * same directory open on their desktop. The Linux cifs kernel
6321 * client hooked into the kernel side of this interface for
6322 * the same reason, but ironically when the VFS moved from
6323 * "dnotify" to "inotify" it became harder to plug in Linux
6324 * network file system clients (the most obvious use case
6325 * for notify interfaces is when multiple users can update
6326 * the contents of the same directory - exactly what network
6327 * file systems can do) although the server (Samba) could
6328 * still use it. For the short term we leave the worker
6329 * function ifdeffed out (below) until inotify is fixed
6330 * in the VFS to make it easier to plug in network file
6331 * system clients. If inotify turns out to be permanently
6332 * incompatible for network fs clients, we could instead simply
6333 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6334 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006335int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006336 const int notify_subdirs, const __u16 netfid,
6337 __u32 filter, struct file *pfile, int multishot,
6338 const struct nls_table *nls_codepage)
6339{
6340 int rc = 0;
6341 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6342 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6343 struct dir_notify_req *dnotify_req;
6344 int bytes_returned;
6345
Joe Perchesf96637b2013-05-04 22:12:25 -05006346 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006347 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6348 (void **) &pSMBr);
6349 if (rc)
6350 return rc;
6351
6352 pSMB->TotalParameterCount = 0 ;
6353 pSMB->TotalDataCount = 0;
6354 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006355 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006356 pSMB->MaxSetupCount = 4;
6357 pSMB->Reserved = 0;
6358 pSMB->ParameterOffset = 0;
6359 pSMB->DataCount = 0;
6360 pSMB->DataOffset = 0;
6361 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6362 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6363 pSMB->ParameterCount = pSMB->TotalParameterCount;
6364 if (notify_subdirs)
6365 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6366 pSMB->Reserved2 = 0;
6367 pSMB->CompletionFilter = cpu_to_le32(filter);
6368 pSMB->Fid = netfid; /* file handle always le */
6369 pSMB->ByteCount = 0;
6370
6371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6372 (struct smb_hdr *)pSMBr, &bytes_returned,
6373 CIFS_ASYNC_OP);
6374 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006375 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006376 } else {
6377 /* Add file to outstanding requests */
6378 /* BB change to kmem cache alloc */
6379 dnotify_req = kmalloc(
6380 sizeof(struct dir_notify_req),
6381 GFP_KERNEL);
6382 if (dnotify_req) {
6383 dnotify_req->Pid = pSMB->hdr.Pid;
6384 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6385 dnotify_req->Mid = pSMB->hdr.Mid;
6386 dnotify_req->Tid = pSMB->hdr.Tid;
6387 dnotify_req->Uid = pSMB->hdr.Uid;
6388 dnotify_req->netfid = netfid;
6389 dnotify_req->pfile = pfile;
6390 dnotify_req->filter = filter;
6391 dnotify_req->multishot = multishot;
6392 spin_lock(&GlobalMid_Lock);
6393 list_add_tail(&dnotify_req->lhead,
6394 &GlobalDnotifyReqList);
6395 spin_unlock(&GlobalMid_Lock);
6396 } else
6397 rc = -ENOMEM;
6398 }
6399 cifs_buf_release(pSMB);
6400 return rc;
6401}
6402#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */