blob: c1c2006376a1743e7956a281359ea8b2965b3989 [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;
Jeff Layton3534b852013-05-24 07:41:01 -0400378 struct TCP_Server_Info *server = ses->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
Jeff Layton3534b852013-05-24 07:41:01 -0400382 if (!server) {
383 WARN(1, "%s: server is NULL!\n", __func__);
384 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
Jeff Layton3534b852013-05-24 07:41:01 -0400386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
388 (void **) &pSMB, (void **) &pSMBr);
389 if (rc)
390 return rc;
Steve French750d1152006-06-27 06:28:30 +0000391
392 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000393 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000394 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000395 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400396 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000397
Joe Perchesf96637b2013-05-04 22:12:25 -0500398 cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000399
Pavel Shilovsky88257362012-05-23 14:01:59 +0400400 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000401 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000402
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000403 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000404 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000405 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500406 cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
Steve Frencha0136892007-10-04 20:05:09 +0000407 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500408 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000409 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
410 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500411 cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000412 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
413 }
Steve French50c2f752007-07-13 00:33:32 +0000414
Steve French39798772006-05-31 22:40:51 +0000415 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000416 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000417 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
418 count += strlen(protocols[i].name) + 1;
419 /* null at end of source and target buffers anyway */
420 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000421 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 pSMB->ByteCount = cpu_to_le16(count);
423
424 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000426 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000427 goto neg_err_exit;
428
Jeff Layton9bf67e52010-04-24 07:57:46 -0400429 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500430 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000431 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400432 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000433 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000434 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000435 could not negotiate a common dialect */
436 rc = -EOPNOTSUPP;
437 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000438#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000439 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400440 && ((server->dialect == LANMAN_PROT)
441 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000442 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000443 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000444
Steve French790fe572007-07-07 19:25:05 +0000445 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000446 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000447 server->secType = LANMAN;
448 else {
Joe Perchesf96637b2013-05-04 22:12:25 -0500449 cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
Steve French39798772006-05-31 22:40:51 +0000450 rc = -EOPNOTSUPP;
451 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000452 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400453 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300454 server->maxReq = min_t(unsigned int,
455 le16_to_cpu(rsp->MaxMpxCount),
456 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400457 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400458 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000459 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000460 /* even though we do not use raw we might as well set this
461 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000462 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000463 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000464 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
465 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000466 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000467 server->capabilities = CAP_MPX_MODE;
468 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000469 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000470 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000471 /* OS/2 often does not set timezone therefore
472 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000473 * Could deviate slightly from the right zone.
474 * Smallest defined timezone difference is 15 minutes
475 * (i.e. Nepal). Rounding up/down is done to match
476 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000477 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000478 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000479 struct timespec ts, utc;
480 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400481 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
482 rsp->SrvTime.Time, 0);
Joe Perchesf96637b2013-05-04 22:12:25 -0500483 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
484 (int)ts.tv_sec, (int)utc.tv_sec,
485 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000486 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000487 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000488 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000489 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000490 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000491 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000492 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000493 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000494 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000495 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000496 server->timeAdj = (int)tmp;
497 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000498 }
Joe Perchesf96637b2013-05-04 22:12:25 -0500499 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000500
Steve French39798772006-05-31 22:40:51 +0000501
Steve French254e55e2006-06-04 05:53:15 +0000502 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000503 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000504
Steve French50c2f752007-07-13 00:33:32 +0000505 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000506 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500507 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000508 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000509 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000510 rc = -EIO; /* need cryptkey unless plain text */
511 goto neg_err_exit;
512 }
Steve French39798772006-05-31 22:40:51 +0000513
Joe Perchesf96637b2013-05-04 22:12:25 -0500514 cifs_dbg(FYI, "LANMAN negotiated\n");
Steve French254e55e2006-06-04 05:53:15 +0000515 /* we will not end up setting signing flags - as no signing
516 was in LANMAN and server did not return the flags on */
517 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000518#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000519 } else if (pSMBr->hdr.WordCount == 13) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500520 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300521 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000522#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000523 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000524 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000525 /* unknown wct */
526 rc = -EOPNOTSUPP;
527 goto neg_err_exit;
528 }
529 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000530 server->sec_mode = pSMBr->SecurityMode;
531 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500532 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000533
Steve French96daf2b2011-05-27 04:34:02 +0000534 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000535#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000536 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000537#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesf96637b2013-05-04 22:12:25 -0500538 cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
Steve French9312f672006-06-04 22:21:07 +0000539
Steve French790fe572007-07-07 19:25:05 +0000540 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000541 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000542 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000543 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000544 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000545 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000546 else if (secFlags & CIFSSEC_MAY_KRB5)
547 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000549 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_LANMAN)
551 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000552 else {
553 rc = -EOPNOTSUPP;
Joe Perchesf96637b2013-05-04 22:12:25 -0500554 cifs_dbg(VFS, "Invalid security type\n");
Steve Frencha0136892007-10-04 20:05:09 +0000555 goto neg_err_exit;
556 }
557 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000558
Steve French254e55e2006-06-04 05:53:15 +0000559 /* one byte, so no need to convert this or EncryptionKeyLen from
560 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300561 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
562 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400563 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000564 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400565 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000566 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500567 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000568 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000569 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
570 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000571 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500572 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000573 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000574 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
575 server->capabilities & CAP_EXTENDED_SECURITY) &&
576 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000577 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400578 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000579 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000581 goto neg_err_exit;
582 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530583 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500584 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530585 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000586 if (memcmp(server->server_GUID,
587 pSMBr->u.extended_response.
588 GUID, 16) != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500589 cifs_dbg(FYI, "server UID changed\n");
Steve French254e55e2006-06-04 05:53:15 +0000590 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000591 pSMBr->u.extended_response.GUID,
592 16);
593 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500594 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530595 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000596 memcpy(server->server_GUID,
597 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 }
Jeff Laytone187e442007-10-16 17:10:44 +0000599
600 if (count == 16) {
601 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000602 } else {
603 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400604 SecurityBlob, count - 16,
605 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000606 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000607 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000608 else
Steve French254e55e2006-06-04 05:53:15 +0000609 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500610 if (server->secType == Kerberos) {
611 if (!server->sec_kerberos &&
612 !server->sec_mskerberos)
613 rc = -EOPNOTSUPP;
614 } else if (server->secType == RawNTLMSSP) {
615 if (!server->sec_ntlmssp)
616 rc = -EOPNOTSUPP;
617 } else
618 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
Steve French96daf2b2011-05-27 04:34:02 +0000620 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000621 rc = -EIO; /* no crypt key only if plain text pwd */
622 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000623 } else
624 server->capabilities &= ~CAP_EXTENDED_SECURITY;
625
Steve French6344a422006-06-12 04:18:35 +0000626#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000627signing_check:
Steve French6344a422006-06-12 04:18:35 +0000628#endif
Steve French762e5ab2007-06-28 18:41:42 +0000629 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
630 /* MUST_SIGN already includes the MAY_SIGN FLAG
631 so if this is zero it means that signing is disabled */
Joe Perchesf96637b2013-05-04 22:12:25 -0500632 cifs_dbg(FYI, "Signing disabled\n");
Steve French96daf2b2011-05-27 04:34:02 +0000633 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500634 cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
Steve Frenchabb63d62007-10-18 02:58:40 +0000635 rc = -EOPNOTSUPP;
636 }
Steve French96daf2b2011-05-27 04:34:02 +0000637 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000638 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000639 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
640 /* signing required */
Joe Perchesf96637b2013-05-04 22:12:25 -0500641 cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000642 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000643 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500644 cifs_dbg(VFS, "signing required but server lacks support\n");
Jeff38c10a12007-07-06 21:10:07 +0000645 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else
Steve French96daf2b2011-05-27 04:34:02 +0000647 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000648 } else {
649 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000650 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
651 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000652 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Steve French50c2f752007-07-13 00:33:32 +0000654
655neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700656 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000657
Joe Perchesf96637b2013-05-04 22:12:25 -0500658 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 return rc;
660}
661
662int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400663CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Joe Perchesf96637b2013-05-04 22:12:25 -0500668 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500669
670 /* BB: do we need to check this? These should never be NULL. */
671 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
672 return -EIO;
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675 * No need to return error on this operation if tid invalidated and
676 * closed on server already e.g. due to tcp session crashing. Also,
677 * the tcon is no longer on the list, so no need to take lock before
678 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 */
Steve French268875b2009-06-25 00:29:21 +0000680 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Steve French50c2f752007-07-13 00:33:32 +0000683 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700684 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500685 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return rc;
Steve French133672e2007-11-13 22:41:37 +0000687
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400688 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500690 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Steve French50c2f752007-07-13 00:33:32 +0000692 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500693 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (rc == -EAGAIN)
695 rc = 0;
696
697 return rc;
698}
699
Jeff Layton766fdbb2011-01-11 07:24:21 -0500700/*
701 * This is a no-op for now. We're not really interested in the reply, but
702 * rather in the fact that the server sent one and that server->lstrp
703 * gets updated.
704 *
705 * FIXME: maybe we should consider checking that the reply matches request?
706 */
707static void
708cifs_echo_callback(struct mid_q_entry *mid)
709{
710 struct TCP_Server_Info *server = mid->callback_data;
711
712 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400713 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500714}
715
716int
717CIFSSMBEcho(struct TCP_Server_Info *server)
718{
719 ECHO_REQ *smb;
720 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400721 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700722 struct smb_rqst rqst = { .rq_iov = &iov,
723 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500724
Joe Perchesf96637b2013-05-04 22:12:25 -0500725 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500726
727 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
728 if (rc)
729 return rc;
730
731 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000732 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500733 smb->hdr.WordCount = 1;
734 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400735 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500736 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000737 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400738 iov.iov_base = smb;
739 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500740
Jeff Laytonfec344e2012-09-18 16:20:35 -0700741 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400742 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500743 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500744 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500745
746 cifs_small_buf_release(smb);
747
748 return rc;
749}
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400752CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 LOGOFF_ANDX_REQ *pSMB;
755 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Joe Perchesf96637b2013-05-04 22:12:25 -0500757 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500758
759 /*
760 * BB: do we need to check validity of ses and server? They should
761 * always be valid since we have an active reference. If not, that
762 * should probably be a BUG()
763 */
764 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return -EIO;
766
Steve Frenchd7b619c2010-02-25 05:36:46 +0000767 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000768 if (ses->need_reconnect)
769 goto session_already_dead; /* no need to send SMBlogoff if uid
770 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
772 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000773 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return rc;
775 }
776
Pavel Shilovsky88257362012-05-23 14:01:59 +0400777 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700778
Steve French96daf2b2011-05-27 04:34:02 +0000779 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
781 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 pSMB->hdr.Uid = ses->Suid;
784
785 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400786 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000787session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000788 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000791 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 error */
793 if (rc == -EAGAIN)
794 rc = 0;
795 return rc;
796}
797
798int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400799CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
800 const char *fileName, __u16 type,
801 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000802{
803 TRANSACTION2_SPI_REQ *pSMB = NULL;
804 TRANSACTION2_SPI_RSP *pSMBr = NULL;
805 struct unlink_psx_rq *pRqD;
806 int name_len;
807 int rc = 0;
808 int bytes_returned = 0;
809 __u16 params, param_offset, offset, byte_count;
810
Joe Perchesf96637b2013-05-04 22:12:25 -0500811 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000812PsxDelete:
813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
814 (void **) &pSMBr);
815 if (rc)
816 return rc;
817
818 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
819 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600820 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
821 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000822 name_len++; /* trailing null */
823 name_len *= 2;
824 } else { /* BB add path length overrun check */
825 name_len = strnlen(fileName, PATH_MAX);
826 name_len++; /* trailing null */
827 strncpy(pSMB->FileName, fileName, name_len);
828 }
829
830 params = 6 + name_len;
831 pSMB->MaxParameterCount = cpu_to_le16(2);
832 pSMB->MaxDataCount = 0; /* BB double check this with jra */
833 pSMB->MaxSetupCount = 0;
834 pSMB->Reserved = 0;
835 pSMB->Flags = 0;
836 pSMB->Timeout = 0;
837 pSMB->Reserved2 = 0;
838 param_offset = offsetof(struct smb_com_transaction2_spi_req,
839 InformationLevel) - 4;
840 offset = param_offset + params;
841
842 /* Setup pointer to Request Data (inode type) */
843 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
844 pRqD->type = cpu_to_le16(type);
845 pSMB->ParameterOffset = cpu_to_le16(param_offset);
846 pSMB->DataOffset = cpu_to_le16(offset);
847 pSMB->SetupCount = 1;
848 pSMB->Reserved3 = 0;
849 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
850 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
851
852 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
853 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
854 pSMB->ParameterCount = cpu_to_le16(params);
855 pSMB->TotalParameterCount = pSMB->ParameterCount;
856 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
857 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000858 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000859 pSMB->ByteCount = cpu_to_le16(byte_count);
860 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
861 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000862 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500863 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000864 cifs_buf_release(pSMB);
865
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400866 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000867
868 if (rc == -EAGAIN)
869 goto PsxDelete;
870
871 return rc;
872}
873
874int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700875CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
876 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 DELETE_FILE_REQ *pSMB = NULL;
879 DELETE_FILE_RSP *pSMBr = NULL;
880 int rc = 0;
881 int bytes_returned;
882 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700883 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885DelFileRetry:
886 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
887 (void **) &pSMBr);
888 if (rc)
889 return rc;
890
891 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700892 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
893 PATH_MAX, cifs_sb->local_nls,
894 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 name_len++; /* trailing null */
896 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700897 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700898 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700900 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
902 pSMB->SearchAttributes =
903 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
904 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000905 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 pSMB->ByteCount = cpu_to_le16(name_len + 1);
907 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
908 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400909 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000910 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500911 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913 cifs_buf_release(pSMB);
914 if (rc == -EAGAIN)
915 goto DelFileRetry;
916
917 return rc;
918}
919
920int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400921CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
922 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
924 DELETE_DIRECTORY_REQ *pSMB = NULL;
925 DELETE_DIRECTORY_RSP *pSMBr = NULL;
926 int rc = 0;
927 int bytes_returned;
928 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400929 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Joe Perchesf96637b2013-05-04 22:12:25 -0500931 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932RmDirRetry:
933 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
934 (void **) &pSMBr);
935 if (rc)
936 return rc;
937
938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400939 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
940 PATH_MAX, cifs_sb->local_nls,
941 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 name_len++; /* trailing null */
943 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700944 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400945 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400947 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 }
949
950 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000951 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 pSMB->ByteCount = cpu_to_le16(name_len + 1);
953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400955 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000956 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500957 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 cifs_buf_release(pSMB);
960 if (rc == -EAGAIN)
961 goto RmDirRetry;
962 return rc;
963}
964
965int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300966CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
967 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
969 int rc = 0;
970 CREATE_DIRECTORY_REQ *pSMB = NULL;
971 CREATE_DIRECTORY_RSP *pSMBr = NULL;
972 int bytes_returned;
973 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300974 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Joe Perchesf96637b2013-05-04 22:12:25 -0500976 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977MkDirRetry:
978 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
982
983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600984 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300985 PATH_MAX, cifs_sb->local_nls,
986 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 name_len++; /* trailing null */
988 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700989 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 name_len = strnlen(name, PATH_MAX);
991 name_len++; /* trailing null */
992 strncpy(pSMB->DirName, name, name_len);
993 }
994
995 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000996 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 pSMB->ByteCount = cpu_to_le16(name_len + 1);
998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001000 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001001 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001002 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 cifs_buf_release(pSMB);
1005 if (rc == -EAGAIN)
1006 goto MkDirRetry;
1007 return rc;
1008}
1009
Steve French2dd29d32007-04-23 22:07:35 +00001010int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001011CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1012 __u32 posix_flags, __u64 mode, __u16 *netfid,
1013 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1014 const char *name, const struct nls_table *nls_codepage,
1015 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001016{
1017 TRANSACTION2_SPI_REQ *pSMB = NULL;
1018 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1019 int name_len;
1020 int rc = 0;
1021 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001022 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001023 OPEN_PSX_REQ *pdata;
1024 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001025
Joe Perchesf96637b2013-05-04 22:12:25 -05001026 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001027PsxCreat:
1028 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1029 (void **) &pSMBr);
1030 if (rc)
1031 return rc;
1032
1033 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1034 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001035 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1036 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001037 name_len++; /* trailing null */
1038 name_len *= 2;
1039 } else { /* BB improve the check for buffer overruns BB */
1040 name_len = strnlen(name, PATH_MAX);
1041 name_len++; /* trailing null */
1042 strncpy(pSMB->FileName, name, name_len);
1043 }
1044
1045 params = 6 + name_len;
1046 count = sizeof(OPEN_PSX_REQ);
1047 pSMB->MaxParameterCount = cpu_to_le16(2);
1048 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1049 pSMB->MaxSetupCount = 0;
1050 pSMB->Reserved = 0;
1051 pSMB->Flags = 0;
1052 pSMB->Timeout = 0;
1053 pSMB->Reserved2 = 0;
1054 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001055 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001056 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001057 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001058 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001059 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001060 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001061 pdata->OpenFlags = cpu_to_le32(*pOplock);
1062 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1063 pSMB->DataOffset = cpu_to_le16(offset);
1064 pSMB->SetupCount = 1;
1065 pSMB->Reserved3 = 0;
1066 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1067 byte_count = 3 /* pad */ + params + count;
1068
1069 pSMB->DataCount = cpu_to_le16(count);
1070 pSMB->ParameterCount = cpu_to_le16(params);
1071 pSMB->TotalDataCount = pSMB->DataCount;
1072 pSMB->TotalParameterCount = pSMB->ParameterCount;
1073 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1074 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001075 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001076 pSMB->ByteCount = cpu_to_le16(byte_count);
1077 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1078 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1079 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001080 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001081 goto psx_create_err;
1082 }
1083
Joe Perchesf96637b2013-05-04 22:12:25 -05001084 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001085 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1086
Jeff Layton820a8032011-05-04 08:05:26 -04001087 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001088 rc = -EIO; /* bad smb */
1089 goto psx_create_err;
1090 }
1091
1092 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001093 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001094 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001095
Steve French2dd29d32007-04-23 22:07:35 +00001096 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001097 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001098 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1099 /* Let caller know file was created so we can set the mode. */
1100 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001101 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001102 *pOplock |= CIFS_CREATE_ACTION;
1103 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001104 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1105 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001106 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001107 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001108 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001109 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001110 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001111 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001112 goto psx_create_err;
1113 }
Steve French50c2f752007-07-13 00:33:32 +00001114 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001115 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001116 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001117 }
Steve French2dd29d32007-04-23 22:07:35 +00001118
1119psx_create_err:
1120 cifs_buf_release(pSMB);
1121
Steve French65bc98b2009-07-10 15:27:25 +00001122 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001123 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001124 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001125 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001126
1127 if (rc == -EAGAIN)
1128 goto PsxCreat;
1129
Steve French50c2f752007-07-13 00:33:32 +00001130 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001131}
1132
Steve Frencha9d02ad2005-08-24 23:06:05 -07001133static __u16 convert_disposition(int disposition)
1134{
1135 __u16 ofun = 0;
1136
1137 switch (disposition) {
1138 case FILE_SUPERSEDE:
1139 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1140 break;
1141 case FILE_OPEN:
1142 ofun = SMBOPEN_OAPPEND;
1143 break;
1144 case FILE_CREATE:
1145 ofun = SMBOPEN_OCREATE;
1146 break;
1147 case FILE_OPEN_IF:
1148 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_OVERWRITE:
1151 ofun = SMBOPEN_OTRUNC;
1152 break;
1153 case FILE_OVERWRITE_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1155 break;
1156 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001157 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001158 ofun = SMBOPEN_OAPPEND; /* regular open */
1159 }
1160 return ofun;
1161}
1162
Jeff Layton35fc37d2008-05-14 10:22:03 -07001163static int
1164access_flags_to_smbopen_mode(const int access_flags)
1165{
1166 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1167
1168 if (masked_flags == GENERIC_READ)
1169 return SMBOPEN_READ;
1170 else if (masked_flags == GENERIC_WRITE)
1171 return SMBOPEN_WRITE;
1172
1173 /* just go for read/write */
1174 return SMBOPEN_READWRITE;
1175}
1176
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001178SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001179 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001180 const int access_flags, const int create_options, __u16 *netfid,
1181 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001182 const struct nls_table *nls_codepage, int remap)
1183{
1184 int rc = -EACCES;
1185 OPENX_REQ *pSMB = NULL;
1186 OPENX_RSP *pSMBr = NULL;
1187 int bytes_returned;
1188 int name_len;
1189 __u16 count;
1190
1191OldOpenRetry:
1192 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1193 (void **) &pSMBr);
1194 if (rc)
1195 return rc;
1196
1197 pSMB->AndXCommand = 0xFF; /* none */
1198
1199 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1200 count = 1; /* account for one byte pad to word boundary */
1201 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001202 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1203 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001204 name_len++; /* trailing null */
1205 name_len *= 2;
1206 } else { /* BB improve check for buffer overruns BB */
1207 count = 0; /* no pad */
1208 name_len = strnlen(fileName, PATH_MAX);
1209 name_len++; /* trailing null */
1210 strncpy(pSMB->fileName, fileName, name_len);
1211 }
1212 if (*pOplock & REQ_OPLOCK)
1213 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001214 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001216
Steve Frencha9d02ad2005-08-24 23:06:05 -07001217 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001218 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1220 /* set file as system file if special file such
1221 as fifo and server expecting SFU style and
1222 no Unix extensions */
1223
Steve French790fe572007-07-07 19:25:05 +00001224 if (create_options & CREATE_OPTION_SPECIAL)
1225 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001226 else /* BB FIXME BB */
1227 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228
Jeff Layton67750fb2008-05-09 22:28:02 +00001229 if (create_options & CREATE_OPTION_READONLY)
1230 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231
1232 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001233/* pSMB->CreateOptions = cpu_to_le32(create_options &
1234 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001236
1237 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001238 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001240 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241
1242 pSMB->ByteCount = cpu_to_le16(count);
1243 /* long_op set to 1 to allow for oplock break timeouts */
1244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001245 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001246 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001248 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 } else {
1250 /* BB verify if wct == 15 */
1251
Steve French582d21e2008-05-13 04:54:12 +00001252/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253
1254 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1255 /* Let caller know file was created so we can set the mode. */
1256 /* Do we care about the CreateAction in any other cases? */
1257 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001258/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 *pOplock |= CIFS_CREATE_ACTION; */
1260 /* BB FIXME END */
1261
Steve French790fe572007-07-07 19:25:05 +00001262 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1264 pfile_info->LastAccessTime = 0; /* BB fixme */
1265 pfile_info->LastWriteTime = 0; /* BB fixme */
1266 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001267 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001268 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001270 pfile_info->AllocationSize =
1271 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1272 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001274 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 }
1276 }
1277
1278 cifs_buf_release(pSMB);
1279 if (rc == -EAGAIN)
1280 goto OldOpenRetry;
1281 return rc;
1282}
1283
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001285CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001287 const int access_flags, const int create_options, __u16 *netfid,
1288 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001289 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
1291 int rc = -EACCES;
1292 OPEN_REQ *pSMB = NULL;
1293 OPEN_RSP *pSMBr = NULL;
1294 int bytes_returned;
1295 int name_len;
1296 __u16 count;
1297
1298openRetry:
1299 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1300 (void **) &pSMBr);
1301 if (rc)
1302 return rc;
1303
1304 pSMB->AndXCommand = 0xFF; /* none */
1305
1306 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1307 count = 1; /* account for one byte pad to word boundary */
1308 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001309 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1310 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 name_len++; /* trailing null */
1312 name_len *= 2;
1313 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001314 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 count = 0; /* no pad */
1316 name_len = strnlen(fileName, PATH_MAX);
1317 name_len++; /* trailing null */
1318 pSMB->NameLength = cpu_to_le16(name_len);
1319 strncpy(pSMB->fileName, fileName, name_len);
1320 }
1321 if (*pOplock & REQ_OPLOCK)
1322 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001323 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1326 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001327 /* set file as system file if special file such
1328 as fifo and server expecting SFU style and
1329 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001330 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001331 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1332 else
1333 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 /* XP does not handle ATTR_POSIX_SEMANTICS */
1336 /* but it helps speed up case sensitive checks for other
1337 servers such as Samba */
1338 if (tcon->ses->capabilities & CAP_UNIX)
1339 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1340
Jeff Layton67750fb2008-05-09 22:28:02 +00001341 if (create_options & CREATE_OPTION_READONLY)
1342 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1343
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1345 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001346 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001347 /* BB Expirement with various impersonation levels and verify */
1348 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 pSMB->SecurityFlags =
1350 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1351
1352 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001353 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
1355 pSMB->ByteCount = cpu_to_le16(count);
1356 /* long_op set to 1 to allow for oplock break timeouts */
1357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001358 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001359 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001361 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 } else {
Steve French09d1db52005-04-28 22:41:08 -07001363 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1365 /* Let caller know file was created so we can set the mode. */
1366 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001367 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001368 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001369 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001370 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1371 36 /* CreationTime to Attributes */);
1372 /* the file_info buf is endian converted by caller */
1373 pfile_info->AllocationSize = pSMBr->AllocationSize;
1374 pfile_info->EndOfFile = pSMBr->EndOfFile;
1375 pfile_info->NumberOfLinks = cpu_to_le32(1);
1376 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 cifs_buf_release(pSMB);
1381 if (rc == -EAGAIN)
1382 goto openRetry;
1383 return rc;
1384}
1385
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001386/*
1387 * Discard any remaining data in the current SMB. To do this, we borrow the
1388 * current bigbuf.
1389 */
1390static int
1391cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1392{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001393 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001394 int remaining = rfclen + 4 - server->total_read;
1395 struct cifs_readdata *rdata = mid->callback_data;
1396
1397 while (remaining > 0) {
1398 int length;
1399
1400 length = cifs_read_from_socket(server, server->bigbuf,
1401 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001402 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001403 if (length < 0)
1404 return length;
1405 server->total_read += length;
1406 remaining -= length;
1407 }
1408
1409 dequeue_mid(mid, rdata->result);
1410 return 0;
1411}
1412
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001413int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001414cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1415{
1416 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001417 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001418 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001419 char *buf = server->smallbuf;
1420 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001421
Joe Perchesf96637b2013-05-04 22:12:25 -05001422 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1423 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001424
1425 /*
1426 * read the rest of READ_RSP header (sans Data array), or whatever we
1427 * can if there's not enough data. At this point, we've read down to
1428 * the Mid.
1429 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001430 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001431 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432
Jeff Layton58195752012-09-19 06:22:34 -07001433 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1434 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001435
Jeff Layton58195752012-09-19 06:22:34 -07001436 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001437 if (length < 0)
1438 return length;
1439 server->total_read += length;
1440
1441 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001442 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001444 cifs_dbg(FYI, "%s: server returned error %d\n",
1445 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446 return cifs_readv_discard(server, mid);
1447 }
1448
1449 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001450 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001451 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1452 __func__, server->total_read,
1453 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001454 rdata->result = -EIO;
1455 return cifs_readv_discard(server, mid);
1456 }
1457
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001458 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001459 if (data_offset < server->total_read) {
1460 /*
1461 * win2k8 sometimes sends an offset of 0 when the read
1462 * is beyond the EOF. Treat it as if the data starts just after
1463 * the header.
1464 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001465 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1466 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001467 data_offset = server->total_read;
1468 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1469 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001470 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1471 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001472 rdata->result = -EIO;
1473 return cifs_readv_discard(server, mid);
1474 }
1475
Joe Perchesf96637b2013-05-04 22:12:25 -05001476 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1477 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001478
1479 len = data_offset - server->total_read;
1480 if (len > 0) {
1481 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001482 rdata->iov.iov_base = buf + server->total_read;
1483 rdata->iov.iov_len = len;
1484 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001485 if (length < 0)
1486 return length;
1487 server->total_read += length;
1488 }
1489
1490 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001491 rdata->iov.iov_base = buf;
1492 rdata->iov.iov_len = server->total_read;
Joe Perchesf96637b2013-05-04 22:12:25 -05001493 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1494 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001495
1496 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001497 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001498 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001499 /* data_len is corrupt -- discard frame */
1500 rdata->result = -EIO;
1501 return cifs_readv_discard(server, mid);
1502 }
1503
Jeff Layton8321fec2012-09-19 06:22:32 -07001504 length = rdata->read_into_pages(server, rdata, data_len);
1505 if (length < 0)
1506 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001507
Jeff Layton8321fec2012-09-19 06:22:32 -07001508 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001509 rdata->bytes = length;
1510
Joe Perchesf96637b2013-05-04 22:12:25 -05001511 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1512 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513
1514 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001515 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516 return cifs_readv_discard(server, mid);
1517
1518 dequeue_mid(mid, false);
1519 return length;
1520}
1521
1522static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001523cifs_readv_callback(struct mid_q_entry *mid)
1524{
1525 struct cifs_readdata *rdata = mid->callback_data;
1526 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1527 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001528 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1529 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001530 .rq_pages = rdata->pages,
1531 .rq_npages = rdata->nr_pages,
1532 .rq_pagesz = rdata->pagesz,
1533 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001534
Joe Perchesf96637b2013-05-04 22:12:25 -05001535 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1536 __func__, mid->mid, mid->mid_state, rdata->result,
1537 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001538
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001539 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001540 case MID_RESPONSE_RECEIVED:
1541 /* result already set, check signature */
1542 if (server->sec_mode &
1543 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001544 int rc = 0;
1545
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001546 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001547 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001548 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001549 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1550 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001551 }
1552 /* FIXME: should this be counted toward the initiating task? */
1553 task_io_account_read(rdata->bytes);
1554 cifs_stats_bytes_read(tcon, rdata->bytes);
1555 break;
1556 case MID_REQUEST_SUBMITTED:
1557 case MID_RETRY_NEEDED:
1558 rdata->result = -EAGAIN;
1559 break;
1560 default:
1561 rdata->result = -EIO;
1562 }
1563
Jeff Laytonda472fc2012-03-23 14:40:53 -04001564 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001565 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001566 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001567}
1568
1569/* cifs_async_readv - send an async write, and set up mid to handle result */
1570int
1571cifs_async_readv(struct cifs_readdata *rdata)
1572{
1573 int rc;
1574 READ_REQ *smb = NULL;
1575 int wct;
1576 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001577 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001578 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001579
Joe Perchesf96637b2013-05-04 22:12:25 -05001580 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1581 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001582
1583 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1584 wct = 12;
1585 else {
1586 wct = 10; /* old style read */
1587 if ((rdata->offset >> 32) > 0) {
1588 /* can not handle this big offset for old */
1589 return -EIO;
1590 }
1591 }
1592
1593 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1594 if (rc)
1595 return rc;
1596
1597 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1598 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1599
1600 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001601 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1603 if (wct == 12)
1604 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1605 smb->Remaining = 0;
1606 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1607 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1608 if (wct == 12)
1609 smb->ByteCount = 0;
1610 else {
1611 /* old style read */
1612 struct smb_com_readx_req *smbr =
1613 (struct smb_com_readx_req *)smb;
1614 smbr->ByteCount = 0;
1615 }
1616
1617 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001618 rdata->iov.iov_base = smb;
1619 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001620
Jeff Layton6993f742012-05-16 07:13:17 -04001621 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001622 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1623 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001624
1625 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001626 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001627 else
1628 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001629
1630 cifs_small_buf_release(smb);
1631 return rc;
1632}
1633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001635CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1636 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637{
1638 int rc = -EACCES;
1639 READ_REQ *pSMB = NULL;
1640 READ_RSP *pSMBr = NULL;
1641 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001642 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001643 int resp_buf_type = 0;
1644 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001645 __u32 pid = io_parms->pid;
1646 __u16 netfid = io_parms->netfid;
1647 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001648 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001649 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Joe Perchesf96637b2013-05-04 22:12:25 -05001651 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001652 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001653 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001654 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001655 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001656 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001657 /* can not handle this big offset for old */
1658 return -EIO;
1659 }
1660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001663 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 if (rc)
1665 return rc;
1666
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001667 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1668 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 /* tcon and ses pointer are checked in smb_init */
1671 if (tcon->ses->server == NULL)
1672 return -ECONNABORTED;
1673
Steve Frenchec637e32005-12-12 20:53:18 -08001674 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001676 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001677 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001678 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001679
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 pSMB->Remaining = 0;
1681 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1682 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001683 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001684 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1685 else {
1686 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001687 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001688 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001689 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001690 }
Steve Frenchec637e32005-12-12 20:53:18 -08001691
1692 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001693 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001694 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001695 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001696 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001697 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001699 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 } else {
1701 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1702 data_length = data_length << 16;
1703 data_length += le16_to_cpu(pSMBr->DataLength);
1704 *nbytes = data_length;
1705
1706 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001707 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001709 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001710 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 rc = -EIO;
1712 *nbytes = 0;
1713 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001714 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001715 le16_to_cpu(pSMBr->DataOffset);
1716/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001717 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001718 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001719 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001720 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001721 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 }
1723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
Steve French4b8f9302006-02-26 16:41:18 +00001725/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001726 if (*buf) {
1727 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001728 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001729 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001730 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001731 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001732 /* return buffer to caller to free */
1733 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001734 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001735 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001736 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001737 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001738 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001739
1740 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 since file handle passed in no longer valid */
1742 return rc;
1743}
1744
Steve Frenchec637e32005-12-12 20:53:18 -08001745
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001747CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001748 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001749 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750{
1751 int rc = -EACCES;
1752 WRITE_REQ *pSMB = NULL;
1753 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001754 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 __u32 bytes_sent;
1756 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001757 __u32 pid = io_parms->pid;
1758 __u16 netfid = io_parms->netfid;
1759 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001760 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001761 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
Steve Frencha24e2d72010-04-03 17:20:21 +00001763 *nbytes = 0;
1764
Joe Perchesf96637b2013-05-04 22:12:25 -05001765 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001766 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001767 return -ECONNABORTED;
1768
Steve French790fe572007-07-07 19:25:05 +00001769 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001770 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001771 else {
Steve French1c955182005-08-30 20:58:07 -07001772 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001773 if ((offset >> 32) > 0) {
1774 /* can not handle big offset for old srv */
1775 return -EIO;
1776 }
1777 }
Steve French1c955182005-08-30 20:58:07 -07001778
1779 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 (void **) &pSMBr);
1781 if (rc)
1782 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001783
1784 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1785 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 /* tcon and ses pointer are checked in smb_init */
1788 if (tcon->ses->server == NULL)
1789 return -ECONNABORTED;
1790
1791 pSMB->AndXCommand = 0xFF; /* none */
1792 pSMB->Fid = netfid;
1793 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001794 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001795 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001796
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 pSMB->Reserved = 0xFFFFFFFF;
1798 pSMB->WriteMode = 0;
1799 pSMB->Remaining = 0;
1800
Steve French50c2f752007-07-13 00:33:32 +00001801 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 can send more if LARGE_WRITE_X capability returned by the server and if
1803 our buffer is big enough or if we convert to iovecs on socket writes
1804 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001805 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1807 } else {
1808 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1809 & ~0xFF;
1810 }
1811
1812 if (bytes_sent > count)
1813 bytes_sent = count;
1814 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001815 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001816 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001817 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001818 else if (ubuf) {
1819 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 cifs_buf_release(pSMB);
1821 return -EFAULT;
1822 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001823 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 /* No buffer */
1825 cifs_buf_release(pSMB);
1826 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001827 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001828 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001829 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001830 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001831 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001832
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1834 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001835 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001836
Steve French790fe572007-07-07 19:25:05 +00001837 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001838 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001839 else { /* old style write has byte count 4 bytes earlier
1840 so 4 bytes pad */
1841 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001842 (struct smb_com_writex_req *)pSMB;
1843 pSMBW->ByteCount = cpu_to_le16(byte_count);
1844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1847 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001848 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001850 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 } else {
1852 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1853 *nbytes = (*nbytes) << 16;
1854 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301855
1856 /*
1857 * Mask off high 16 bits when bytes written as returned by the
1858 * server is greater than bytes requested by the client. Some
1859 * OS/2 servers are known to set incorrect CountHigh values.
1860 */
1861 if (*nbytes > count)
1862 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 }
1864
1865 cifs_buf_release(pSMB);
1866
Steve French50c2f752007-07-13 00:33:32 +00001867 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 since file handle passed in no longer valid */
1869
1870 return rc;
1871}
1872
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001873void
1874cifs_writedata_release(struct kref *refcount)
1875{
1876 struct cifs_writedata *wdata = container_of(refcount,
1877 struct cifs_writedata, refcount);
1878
1879 if (wdata->cfile)
1880 cifsFileInfo_put(wdata->cfile);
1881
1882 kfree(wdata);
1883}
1884
1885/*
1886 * Write failed with a retryable error. Resend the write request. It's also
1887 * possible that the page was redirtied so re-clean the page.
1888 */
1889static void
1890cifs_writev_requeue(struct cifs_writedata *wdata)
1891{
1892 int i, rc;
1893 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001894 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001895
1896 for (i = 0; i < wdata->nr_pages; i++) {
1897 lock_page(wdata->pages[i]);
1898 clear_page_dirty_for_io(wdata->pages[i]);
1899 }
1900
1901 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001902 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1903 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001904 } while (rc == -EAGAIN);
1905
1906 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001907 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001908 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001909 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001910 end_page_writeback(wdata->pages[i]);
1911 page_cache_release(wdata->pages[i]);
1912 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001913 }
1914
1915 mapping_set_error(inode->i_mapping, rc);
1916 kref_put(&wdata->refcount, cifs_writedata_release);
1917}
1918
Jeff Laytonc2e87642012-03-23 14:40:55 -04001919void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001920cifs_writev_complete(struct work_struct *work)
1921{
1922 struct cifs_writedata *wdata = container_of(work,
1923 struct cifs_writedata, work);
1924 struct inode *inode = wdata->cfile->dentry->d_inode;
1925 int i = 0;
1926
1927 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001928 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001929 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001930 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001931 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1932 wdata->bytes);
1933 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1934 return cifs_writev_requeue(wdata);
1935
1936 for (i = 0; i < wdata->nr_pages; i++) {
1937 struct page *page = wdata->pages[i];
1938 if (wdata->result == -EAGAIN)
1939 __set_page_dirty_nobuffers(page);
1940 else if (wdata->result < 0)
1941 SetPageError(page);
1942 end_page_writeback(page);
1943 page_cache_release(page);
1944 }
1945 if (wdata->result != -EAGAIN)
1946 mapping_set_error(inode->i_mapping, wdata->result);
1947 kref_put(&wdata->refcount, cifs_writedata_release);
1948}
1949
1950struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001951cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001952{
1953 struct cifs_writedata *wdata;
1954
1955 /* this would overflow */
1956 if (nr_pages == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001957 cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001958 return NULL;
1959 }
1960
1961 /* writedata + number of page pointers */
1962 wdata = kzalloc(sizeof(*wdata) +
1963 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1964 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001965 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001966 INIT_LIST_HEAD(&wdata->list);
1967 init_completion(&wdata->done);
1968 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001969 }
1970 return wdata;
1971}
1972
1973/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001974 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001975 * workqueue completion task.
1976 */
1977static void
1978cifs_writev_callback(struct mid_q_entry *mid)
1979{
1980 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001981 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001982 unsigned int written;
1983 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1984
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001985 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001986 case MID_RESPONSE_RECEIVED:
1987 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1988 if (wdata->result != 0)
1989 break;
1990
1991 written = le16_to_cpu(smb->CountHigh);
1992 written <<= 16;
1993 written += le16_to_cpu(smb->Count);
1994 /*
1995 * Mask off high 16 bits when bytes written as returned
1996 * by the server is greater than bytes requested by the
1997 * client. OS/2 servers are known to set incorrect
1998 * CountHigh values.
1999 */
2000 if (written > wdata->bytes)
2001 written &= 0xFFFF;
2002
2003 if (written < wdata->bytes)
2004 wdata->result = -ENOSPC;
2005 else
2006 wdata->bytes = written;
2007 break;
2008 case MID_REQUEST_SUBMITTED:
2009 case MID_RETRY_NEEDED:
2010 wdata->result = -EAGAIN;
2011 break;
2012 default:
2013 wdata->result = -EIO;
2014 break;
2015 }
2016
Jeff Laytonda472fc2012-03-23 14:40:53 -04002017 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002018 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002019 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002020}
2021
2022/* cifs_async_writev - send an async write, and set up mid to handle result */
2023int
2024cifs_async_writev(struct cifs_writedata *wdata)
2025{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002026 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002027 WRITE_REQ *smb = NULL;
2028 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002029 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002030 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002031 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002032
2033 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2034 wct = 14;
2035 } else {
2036 wct = 12;
2037 if (wdata->offset >> 32 > 0) {
2038 /* can not handle big offset for old srv */
2039 return -EIO;
2040 }
2041 }
2042
2043 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2044 if (rc)
2045 goto async_writev_out;
2046
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002047 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2048 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002049
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002050 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002051 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2053 if (wct == 14)
2054 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2055 smb->Reserved = 0xFFFFFFFF;
2056 smb->WriteMode = 0;
2057 smb->Remaining = 0;
2058
2059 smb->DataOffset =
2060 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2061
2062 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002063 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2064 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002065
Jeff Laytoneddb0792012-09-18 16:20:35 -07002066 rqst.rq_iov = &iov;
2067 rqst.rq_nvec = 1;
2068 rqst.rq_pages = wdata->pages;
2069 rqst.rq_npages = wdata->nr_pages;
2070 rqst.rq_pagesz = wdata->pagesz;
2071 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002072
Joe Perchesf96637b2013-05-04 22:12:25 -05002073 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2074 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002075
2076 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2077 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2078
2079 if (wct == 14) {
2080 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2081 put_bcc(wdata->bytes + 1, &smb->hdr);
2082 } else {
2083 /* wct == 12 */
2084 struct smb_com_writex_req *smbw =
2085 (struct smb_com_writex_req *)smb;
2086 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2087 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002088 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002089 }
2090
2091 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002092 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2093 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094
2095 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002096 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002097 else
2098 kref_put(&wdata->refcount, cifs_writedata_release);
2099
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002100async_writev_out:
2101 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102 return rc;
2103}
2104
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002105int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002106CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002107 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
2109 int rc = -EACCES;
2110 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002111 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002112 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002113 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002114 __u32 pid = io_parms->pid;
2115 __u16 netfid = io_parms->netfid;
2116 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002117 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002118 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002120 *nbytes = 0;
2121
Joe Perchesf96637b2013-05-04 22:12:25 -05002122 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002123
Steve French4c3130e2008-12-09 00:28:16 +00002124 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002125 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002126 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002127 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002128 if ((offset >> 32) > 0) {
2129 /* can not handle big offset for old srv */
2130 return -EIO;
2131 }
2132 }
Steve French8cc64c62005-10-03 13:49:43 -07002133 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 if (rc)
2135 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002136
2137 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2138 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2139
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 /* tcon and ses pointer are checked in smb_init */
2141 if (tcon->ses->server == NULL)
2142 return -ECONNABORTED;
2143
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002144 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 pSMB->Fid = netfid;
2146 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002147 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002148 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 pSMB->Reserved = 0xFFFFFFFF;
2150 pSMB->WriteMode = 0;
2151 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002154 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
Steve French3e844692005-10-03 13:37:24 -07002156 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2157 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002158 /* header + 1 byte pad */
2159 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002160 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002161 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002162 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002163 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002164 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002165 pSMB->ByteCount = cpu_to_le16(count + 1);
2166 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002167 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002168 (struct smb_com_writex_req *)pSMB;
2169 pSMBW->ByteCount = cpu_to_le16(count + 5);
2170 }
Steve French3e844692005-10-03 13:37:24 -07002171 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002172 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002173 iov[0].iov_len = smb_hdr_len + 4;
2174 else /* wct == 12 pad bigger by four bytes */
2175 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002176
Steve French3e844692005-10-03 13:37:24 -07002177
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002178 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002179 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002181 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002182 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002183 /* presumably this can not happen, but best to be safe */
2184 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002185 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002186 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002187 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2188 *nbytes = (*nbytes) << 16;
2189 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302190
2191 /*
2192 * Mask off high 16 bits when bytes written as returned by the
2193 * server is greater than bytes requested by the client. OS/2
2194 * servers are known to set incorrect CountHigh values.
2195 */
2196 if (*nbytes > count)
2197 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Steve French4b8f9302006-02-26 16:41:18 +00002200/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002201 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002202 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002203 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002204 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
Steve French50c2f752007-07-13 00:33:32 +00002206 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 since file handle passed in no longer valid */
2208
2209 return rc;
2210}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002211
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002212int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2213 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002214 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2215{
2216 int rc = 0;
2217 LOCK_REQ *pSMB = NULL;
2218 struct kvec iov[2];
2219 int resp_buf_type;
2220 __u16 count;
2221
Joe Perchesf96637b2013-05-04 22:12:25 -05002222 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2223 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002224
2225 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2226 if (rc)
2227 return rc;
2228
2229 pSMB->Timeout = 0;
2230 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2231 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2232 pSMB->LockType = lock_type;
2233 pSMB->AndXCommand = 0xFF; /* none */
2234 pSMB->Fid = netfid; /* netfid stays le */
2235
2236 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2237 inc_rfc1001_len(pSMB, count);
2238 pSMB->ByteCount = cpu_to_le16(count);
2239
2240 iov[0].iov_base = (char *)pSMB;
2241 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2242 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2243 iov[1].iov_base = (char *)buf;
2244 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2245
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002246 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002247 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2248 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002249 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002250
2251 return rc;
2252}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002255CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002256 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002258 const __u32 numLock, const __u8 lockType,
2259 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260{
2261 int rc = 0;
2262 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002263/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002265 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 __u16 count;
2267
Joe Perchesf96637b2013-05-04 22:12:25 -05002268 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2269 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002270 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2271
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 if (rc)
2273 return rc;
2274
Steve French790fe572007-07-07 19:25:05 +00002275 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002276 /* no response expected */
2277 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002279 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002280 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2282 } else {
2283 pSMB->Timeout = 0;
2284 }
2285
2286 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2287 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2288 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002289 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 pSMB->AndXCommand = 0xFF; /* none */
2291 pSMB->Fid = smb_file_id; /* netfid stays le */
2292
Steve French790fe572007-07-07 19:25:05 +00002293 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002294 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 /* BB where to store pid high? */
2296 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2297 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2298 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2299 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2300 count = sizeof(LOCKING_ANDX_RANGE);
2301 } else {
2302 /* oplock break */
2303 count = 0;
2304 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002305 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 pSMB->ByteCount = cpu_to_le16(count);
2307
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002308 if (waitFlag) {
2309 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002310 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002311 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002312 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002313 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002314 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002315 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002316 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002317 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002318 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Steve French50c2f752007-07-13 00:33:32 +00002320 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 since file handle passed in no longer valid */
2322 return rc;
2323}
2324
2325int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002326CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002327 const __u16 smb_file_id, const __u32 netpid,
2328 const loff_t start_offset, const __u64 len,
2329 struct file_lock *pLockData, const __u16 lock_type,
2330 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002331{
2332 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2333 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002334 struct cifs_posix_lock *parm_data;
2335 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002336 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002337 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002338 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002339 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002340 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002341
Joe Perchesf96637b2013-05-04 22:12:25 -05002342 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002343
Steve French08547b02006-02-28 22:39:25 +00002344 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2345
2346 if (rc)
2347 return rc;
2348
2349 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2350
Steve French50c2f752007-07-13 00:33:32 +00002351 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002352 pSMB->MaxSetupCount = 0;
2353 pSMB->Reserved = 0;
2354 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002355 pSMB->Reserved2 = 0;
2356 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2357 offset = param_offset + params;
2358
Steve French08547b02006-02-28 22:39:25 +00002359 count = sizeof(struct cifs_posix_lock);
2360 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002361 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002362 pSMB->SetupCount = 1;
2363 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002364 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002365 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2366 else
2367 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2368 byte_count = 3 /* pad */ + params + count;
2369 pSMB->DataCount = cpu_to_le16(count);
2370 pSMB->ParameterCount = cpu_to_le16(params);
2371 pSMB->TotalDataCount = pSMB->DataCount;
2372 pSMB->TotalParameterCount = pSMB->ParameterCount;
2373 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002374 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002375 (((char *) &pSMB->hdr.Protocol) + offset);
2376
2377 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002378 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002379 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002380 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002381 pSMB->Timeout = cpu_to_le32(-1);
2382 } else
2383 pSMB->Timeout = 0;
2384
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002385 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002386 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002387 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002388
2389 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002390 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002391 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2392 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002393 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002394 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002395 if (waitFlag) {
2396 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2397 (struct smb_hdr *) pSMBr, &bytes_returned);
2398 } else {
Steve French133672e2007-11-13 22:41:37 +00002399 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002400 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002401 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2402 &resp_buf_type, timeout);
2403 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2404 not try to free it twice below on exit */
2405 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002406 }
2407
Steve French08547b02006-02-28 22:39:25 +00002408 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002409 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002410 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002411 /* lock structure can be returned on get */
2412 __u16 data_offset;
2413 __u16 data_count;
2414 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002415
Jeff Layton820a8032011-05-04 08:05:26 -04002416 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002417 rc = -EIO; /* bad smb */
2418 goto plk_err_exit;
2419 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002420 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2421 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002422 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002423 rc = -EIO;
2424 goto plk_err_exit;
2425 }
2426 parm_data = (struct cifs_posix_lock *)
2427 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002428 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002429 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002430 else {
2431 if (parm_data->lock_type ==
2432 __constant_cpu_to_le16(CIFS_RDLCK))
2433 pLockData->fl_type = F_RDLCK;
2434 else if (parm_data->lock_type ==
2435 __constant_cpu_to_le16(CIFS_WRLCK))
2436 pLockData->fl_type = F_WRLCK;
2437
Steve French5443d132011-03-13 05:08:25 +00002438 pLockData->fl_start = le64_to_cpu(parm_data->start);
2439 pLockData->fl_end = pLockData->fl_start +
2440 le64_to_cpu(parm_data->length) - 1;
2441 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002442 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002443 }
Steve French50c2f752007-07-13 00:33:32 +00002444
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002445plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002446 if (pSMB)
2447 cifs_small_buf_release(pSMB);
2448
Steve French133672e2007-11-13 22:41:37 +00002449 if (resp_buf_type == CIFS_SMALL_BUFFER)
2450 cifs_small_buf_release(iov[0].iov_base);
2451 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2452 cifs_buf_release(iov[0].iov_base);
2453
Steve French08547b02006-02-28 22:39:25 +00002454 /* Note: On -EAGAIN error only caller can retry on handle based calls
2455 since file handle passed in no longer valid */
2456
2457 return rc;
2458}
2459
2460
2461int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002462CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463{
2464 int rc = 0;
2465 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002466 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468/* do not retry on dead session on close */
2469 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002470 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 return 0;
2472 if (rc)
2473 return rc;
2474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002476 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002478 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002479 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002481 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002483 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 }
2486
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002488 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 rc = 0;
2490
2491 return rc;
2492}
2493
2494int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002495CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002496{
2497 int rc = 0;
2498 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002499 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002500
2501 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2502 if (rc)
2503 return rc;
2504
2505 pSMB->FileID = (__u16) smb_file_id;
2506 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002507 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002508 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002509 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002510 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002511
2512 return rc;
2513}
2514
2515int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002516CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002517 const char *from_name, const char *to_name,
2518 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519{
2520 int rc = 0;
2521 RENAME_REQ *pSMB = NULL;
2522 RENAME_RSP *pSMBr = NULL;
2523 int bytes_returned;
2524 int name_len, name_len2;
2525 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002526 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
Joe Perchesf96637b2013-05-04 22:12:25 -05002528 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529renameRetry:
2530 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2531 (void **) &pSMBr);
2532 if (rc)
2533 return rc;
2534
2535 pSMB->BufferFormat = 0x04;
2536 pSMB->SearchAttributes =
2537 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2538 ATTR_DIRECTORY);
2539
2540 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002541 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2542 from_name, PATH_MAX,
2543 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 name_len++; /* trailing null */
2545 name_len *= 2;
2546 pSMB->OldFileName[name_len] = 0x04; /* pad */
2547 /* protocol requires ASCII signature byte on Unicode string */
2548 pSMB->OldFileName[name_len + 1] = 0x00;
2549 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002550 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002551 to_name, PATH_MAX, cifs_sb->local_nls,
2552 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2554 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002555 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002556 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002558 strncpy(pSMB->OldFileName, from_name, name_len);
2559 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 name_len2++; /* trailing null */
2561 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002562 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 name_len2++; /* trailing null */
2564 name_len2++; /* signature byte */
2565 }
2566
2567 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002568 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 pSMB->ByteCount = cpu_to_le16(count);
2570
2571 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2572 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002573 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002574 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002575 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 cifs_buf_release(pSMB);
2578
2579 if (rc == -EAGAIN)
2580 goto renameRetry;
2581
2582 return rc;
2583}
2584
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002585int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002586 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002587 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588{
2589 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2590 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002591 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 char *data_offset;
2593 char dummy_string[30];
2594 int rc = 0;
2595 int bytes_returned = 0;
2596 int len_of_str;
2597 __u16 params, param_offset, offset, count, byte_count;
2598
Joe Perchesf96637b2013-05-04 22:12:25 -05002599 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2601 (void **) &pSMBr);
2602 if (rc)
2603 return rc;
2604
2605 params = 6;
2606 pSMB->MaxSetupCount = 0;
2607 pSMB->Reserved = 0;
2608 pSMB->Flags = 0;
2609 pSMB->Timeout = 0;
2610 pSMB->Reserved2 = 0;
2611 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2612 offset = param_offset + params;
2613
2614 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2615 rename_info = (struct set_file_rename *) data_offset;
2616 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002617 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 pSMB->SetupCount = 1;
2619 pSMB->Reserved3 = 0;
2620 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2621 byte_count = 3 /* pad */ + params;
2622 pSMB->ParameterCount = cpu_to_le16(params);
2623 pSMB->TotalParameterCount = pSMB->ParameterCount;
2624 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2625 pSMB->DataOffset = cpu_to_le16(offset);
2626 /* construct random name ".cifs_tmp<inodenum><mid>" */
2627 rename_info->overwrite = cpu_to_le32(1);
2628 rename_info->root_fid = 0;
2629 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002630 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002631 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002632 len_of_str =
2633 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002634 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002636 len_of_str =
2637 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002638 target_name, PATH_MAX, nls_codepage,
2639 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002642 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 byte_count += count;
2644 pSMB->DataCount = cpu_to_le16(count);
2645 pSMB->TotalDataCount = pSMB->DataCount;
2646 pSMB->Fid = netfid;
2647 pSMB->InformationLevel =
2648 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2649 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002650 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 pSMB->ByteCount = cpu_to_le16(byte_count);
2652 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002654 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002655 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002656 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2657 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002658
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 cifs_buf_release(pSMB);
2660
2661 /* Note: On -EAGAIN error only caller can retry on handle based calls
2662 since file handle passed in no longer valid */
2663
2664 return rc;
2665}
2666
2667int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002668CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2669 const char *fromName, const __u16 target_tid, const char *toName,
2670 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671{
2672 int rc = 0;
2673 COPY_REQ *pSMB = NULL;
2674 COPY_RSP *pSMBr = NULL;
2675 int bytes_returned;
2676 int name_len, name_len2;
2677 __u16 count;
2678
Joe Perchesf96637b2013-05-04 22:12:25 -05002679 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680copyRetry:
2681 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2682 (void **) &pSMBr);
2683 if (rc)
2684 return rc;
2685
2686 pSMB->BufferFormat = 0x04;
2687 pSMB->Tid2 = target_tid;
2688
2689 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2690
2691 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002692 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2693 fromName, PATH_MAX, nls_codepage,
2694 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 name_len++; /* trailing null */
2696 name_len *= 2;
2697 pSMB->OldFileName[name_len] = 0x04; /* pad */
2698 /* protocol requires ASCII signature byte on Unicode string */
2699 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002700 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002701 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2702 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2704 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002705 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 name_len = strnlen(fromName, PATH_MAX);
2707 name_len++; /* trailing null */
2708 strncpy(pSMB->OldFileName, fromName, name_len);
2709 name_len2 = strnlen(toName, PATH_MAX);
2710 name_len2++; /* trailing null */
2711 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2712 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2713 name_len2++; /* trailing null */
2714 name_len2++; /* signature byte */
2715 }
2716
2717 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002718 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 pSMB->ByteCount = cpu_to_le16(count);
2720
2721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2723 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002724 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2725 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 }
Steve French0d817bc2008-05-22 02:02:03 +00002727 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
2729 if (rc == -EAGAIN)
2730 goto copyRetry;
2731
2732 return rc;
2733}
2734
2735int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002736CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 const char *fromName, const char *toName,
2738 const struct nls_table *nls_codepage)
2739{
2740 TRANSACTION2_SPI_REQ *pSMB = NULL;
2741 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2742 char *data_offset;
2743 int name_len;
2744 int name_len_target;
2745 int rc = 0;
2746 int bytes_returned = 0;
2747 __u16 params, param_offset, offset, byte_count;
2748
Joe Perchesf96637b2013-05-04 22:12:25 -05002749 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750createSymLinkRetry:
2751 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2752 (void **) &pSMBr);
2753 if (rc)
2754 return rc;
2755
2756 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2757 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002758 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2759 /* find define for this maxpathcomponent */
2760 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 name_len++; /* trailing null */
2762 name_len *= 2;
2763
Steve French50c2f752007-07-13 00:33:32 +00002764 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 name_len = strnlen(fromName, PATH_MAX);
2766 name_len++; /* trailing null */
2767 strncpy(pSMB->FileName, fromName, name_len);
2768 }
2769 params = 6 + name_len;
2770 pSMB->MaxSetupCount = 0;
2771 pSMB->Reserved = 0;
2772 pSMB->Flags = 0;
2773 pSMB->Timeout = 0;
2774 pSMB->Reserved2 = 0;
2775 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002776 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 offset = param_offset + params;
2778
2779 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2780 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2781 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002782 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2783 /* find define for this maxpathcomponent */
2784 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 name_len_target++; /* trailing null */
2786 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002787 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 name_len_target = strnlen(toName, PATH_MAX);
2789 name_len_target++; /* trailing null */
2790 strncpy(data_offset, toName, name_len_target);
2791 }
2792
2793 pSMB->MaxParameterCount = cpu_to_le16(2);
2794 /* BB find exact max on data count below from sess */
2795 pSMB->MaxDataCount = cpu_to_le16(1000);
2796 pSMB->SetupCount = 1;
2797 pSMB->Reserved3 = 0;
2798 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2799 byte_count = 3 /* pad */ + params + name_len_target;
2800 pSMB->DataCount = cpu_to_le16(name_len_target);
2801 pSMB->ParameterCount = cpu_to_le16(params);
2802 pSMB->TotalDataCount = pSMB->DataCount;
2803 pSMB->TotalParameterCount = pSMB->ParameterCount;
2804 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2805 pSMB->DataOffset = cpu_to_le16(offset);
2806 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2807 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002808 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 pSMB->ByteCount = cpu_to_le16(byte_count);
2810 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002812 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002813 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002814 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2815 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
Steve French0d817bc2008-05-22 02:02:03 +00002817 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
2819 if (rc == -EAGAIN)
2820 goto createSymLinkRetry;
2821
2822 return rc;
2823}
2824
2825int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002826CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002828 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829{
2830 TRANSACTION2_SPI_REQ *pSMB = NULL;
2831 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2832 char *data_offset;
2833 int name_len;
2834 int name_len_target;
2835 int rc = 0;
2836 int bytes_returned = 0;
2837 __u16 params, param_offset, offset, byte_count;
2838
Joe Perchesf96637b2013-05-04 22:12:25 -05002839 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840createHardLinkRetry:
2841 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2842 (void **) &pSMBr);
2843 if (rc)
2844 return rc;
2845
2846 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002847 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2848 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 name_len++; /* trailing null */
2850 name_len *= 2;
2851
Steve French50c2f752007-07-13 00:33:32 +00002852 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len = strnlen(toName, PATH_MAX);
2854 name_len++; /* trailing null */
2855 strncpy(pSMB->FileName, toName, name_len);
2856 }
2857 params = 6 + name_len;
2858 pSMB->MaxSetupCount = 0;
2859 pSMB->Reserved = 0;
2860 pSMB->Flags = 0;
2861 pSMB->Timeout = 0;
2862 pSMB->Reserved2 = 0;
2863 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002864 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 offset = param_offset + params;
2866
2867 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2869 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002870 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2871 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 name_len_target++; /* trailing null */
2873 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002874 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len_target = strnlen(fromName, PATH_MAX);
2876 name_len_target++; /* trailing null */
2877 strncpy(data_offset, fromName, name_len_target);
2878 }
2879
2880 pSMB->MaxParameterCount = cpu_to_le16(2);
2881 /* BB find exact max on data count below from sess*/
2882 pSMB->MaxDataCount = cpu_to_le16(1000);
2883 pSMB->SetupCount = 1;
2884 pSMB->Reserved3 = 0;
2885 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2886 byte_count = 3 /* pad */ + params + name_len_target;
2887 pSMB->ParameterCount = cpu_to_le16(params);
2888 pSMB->TotalParameterCount = pSMB->ParameterCount;
2889 pSMB->DataCount = cpu_to_le16(name_len_target);
2890 pSMB->TotalDataCount = pSMB->DataCount;
2891 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2892 pSMB->DataOffset = cpu_to_le16(offset);
2893 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2894 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002895 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 pSMB->ByteCount = cpu_to_le16(byte_count);
2897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002899 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002900 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002901 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
2902 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
2904 cifs_buf_release(pSMB);
2905 if (rc == -EAGAIN)
2906 goto createHardLinkRetry;
2907
2908 return rc;
2909}
2910
2911int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002912CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002913 const char *from_name, const char *to_name,
2914 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916 int rc = 0;
2917 NT_RENAME_REQ *pSMB = NULL;
2918 RENAME_RSP *pSMBr = NULL;
2919 int bytes_returned;
2920 int name_len, name_len2;
2921 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002922 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Joe Perchesf96637b2013-05-04 22:12:25 -05002924 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925winCreateHardLinkRetry:
2926
2927 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2928 (void **) &pSMBr);
2929 if (rc)
2930 return rc;
2931
2932 pSMB->SearchAttributes =
2933 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2934 ATTR_DIRECTORY);
2935 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2936 pSMB->ClusterCount = 0;
2937
2938 pSMB->BufferFormat = 0x04;
2939
2940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2941 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002942 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2943 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 name_len++; /* trailing null */
2945 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002946
2947 /* protocol specifies ASCII buffer format (0x04) for unicode */
2948 pSMB->OldFileName[name_len] = 0x04;
2949 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002951 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002952 to_name, PATH_MAX, cifs_sb->local_nls,
2953 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2955 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002956 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002957 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002959 strncpy(pSMB->OldFileName, from_name, name_len);
2960 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 name_len2++; /* trailing null */
2962 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002963 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len2++; /* trailing null */
2965 name_len2++; /* signature byte */
2966 }
2967
2968 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002969 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 pSMB->ByteCount = cpu_to_le16(count);
2971
2972 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2973 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002974 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002975 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002976 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002977
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 cifs_buf_release(pSMB);
2979 if (rc == -EAGAIN)
2980 goto winCreateHardLinkRetry;
2981
2982 return rc;
2983}
2984
2985int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002986CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002987 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 const struct nls_table *nls_codepage)
2989{
2990/* SMB_QUERY_FILE_UNIX_LINK */
2991 TRANSACTION2_QPI_REQ *pSMB = NULL;
2992 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2993 int rc = 0;
2994 int bytes_returned;
2995 int name_len;
2996 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002997 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998
Joe Perchesf96637b2013-05-04 22:12:25 -05002999 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000
3001querySymLinkRetry:
3002 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3003 (void **) &pSMBr);
3004 if (rc)
3005 return rc;
3006
3007 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3008 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003009 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3010 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 name_len++; /* trailing null */
3012 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003013 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 name_len = strnlen(searchName, PATH_MAX);
3015 name_len++; /* trailing null */
3016 strncpy(pSMB->FileName, searchName, name_len);
3017 }
3018
3019 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3020 pSMB->TotalDataCount = 0;
3021 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003022 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 pSMB->MaxSetupCount = 0;
3024 pSMB->Reserved = 0;
3025 pSMB->Flags = 0;
3026 pSMB->Timeout = 0;
3027 pSMB->Reserved2 = 0;
3028 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003029 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 pSMB->DataCount = 0;
3031 pSMB->DataOffset = 0;
3032 pSMB->SetupCount = 1;
3033 pSMB->Reserved3 = 0;
3034 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3035 byte_count = params + 1 /* pad */ ;
3036 pSMB->TotalParameterCount = cpu_to_le16(params);
3037 pSMB->ParameterCount = pSMB->TotalParameterCount;
3038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3039 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003040 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 pSMB->ByteCount = cpu_to_le16(byte_count);
3042
3043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3045 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003046 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 } else {
3048 /* decode response */
3049
3050 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003052 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003053 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003055 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003056 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
Jeff Layton460b9692009-04-30 07:17:56 -04003058 data_start = ((char *) &pSMBr->hdr.Protocol) +
3059 le16_to_cpu(pSMBr->t2.DataOffset);
3060
Steve French0e0d2cf2009-05-01 05:27:32 +00003061 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3062 is_unicode = true;
3063 else
3064 is_unicode = false;
3065
Steve French737b7582005-04-28 22:41:06 -07003066 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003067 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3068 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003069 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003070 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 }
3072 }
3073 cifs_buf_release(pSMB);
3074 if (rc == -EAGAIN)
3075 goto querySymLinkRetry;
3076 return rc;
3077}
3078
Steve Frenchc52a95542011-02-24 06:16:22 +00003079#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3080/*
3081 * Recent Windows versions now create symlinks more frequently
3082 * and they use the "reparse point" mechanism below. We can of course
3083 * do symlinks nicely to Samba and other servers which support the
3084 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3085 * "MF" symlinks optionally, but for recent Windows we really need to
3086 * reenable the code below and fix the cifs_symlink callers to handle this.
3087 * In the interim this code has been moved to its own config option so
3088 * it is not compiled in by default until callers fixed up and more tested.
3089 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003091CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003093 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 const struct nls_table *nls_codepage)
3095{
3096 int rc = 0;
3097 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003098 struct smb_com_transaction_ioctl_req *pSMB;
3099 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Joe Perchesf96637b2013-05-04 22:12:25 -05003101 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
3102 searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3104 (void **) &pSMBr);
3105 if (rc)
3106 return rc;
3107
3108 pSMB->TotalParameterCount = 0 ;
3109 pSMB->TotalDataCount = 0;
3110 pSMB->MaxParameterCount = cpu_to_le32(2);
3111 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003112 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 pSMB->MaxSetupCount = 4;
3114 pSMB->Reserved = 0;
3115 pSMB->ParameterOffset = 0;
3116 pSMB->DataCount = 0;
3117 pSMB->DataOffset = 0;
3118 pSMB->SetupCount = 4;
3119 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3120 pSMB->ParameterCount = pSMB->TotalParameterCount;
3121 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3122 pSMB->IsFsctl = 1; /* FSCTL */
3123 pSMB->IsRootFlag = 0;
3124 pSMB->Fid = fid; /* file handle always le */
3125 pSMB->ByteCount = 0;
3126
3127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3129 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003130 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 } else { /* decode response */
3132 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3133 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003134 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3135 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003137 goto qreparse_out;
3138 }
3139 if (data_count && (data_count < 2048)) {
3140 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003141 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142
Steve Frenchafe48c32009-05-02 05:25:46 +00003143 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003144 (struct reparse_data *)
3145 ((char *)&pSMBr->hdr.Protocol
3146 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003147 if ((char *)reparse_buf >= end_of_smb) {
3148 rc = -EIO;
3149 goto qreparse_out;
3150 }
3151 if ((reparse_buf->LinkNamesBuf +
3152 reparse_buf->TargetNameOffset +
3153 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003154 cifs_dbg(FYI, "reparse buf beyond SMB\n");
Steve Frenchafe48c32009-05-02 05:25:46 +00003155 rc = -EIO;
3156 goto qreparse_out;
3157 }
Steve French50c2f752007-07-13 00:33:32 +00003158
Steve Frenchafe48c32009-05-02 05:25:46 +00003159 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3160 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003161 (reparse_buf->LinkNamesBuf +
3162 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003163 buflen,
3164 reparse_buf->TargetNameLen,
3165 nls_codepage, 0);
3166 } else { /* ASCII names */
3167 strncpy(symlinkinfo,
3168 reparse_buf->LinkNamesBuf +
3169 reparse_buf->TargetNameOffset,
3170 min_t(const int, buflen,
3171 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003173 } else {
3174 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -05003175 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003177 symlinkinfo[buflen] = 0; /* just in case so the caller
3178 does not go off the end of the buffer */
Joe Perchesf96637b2013-05-04 22:12:25 -05003179 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 }
Steve French989c7e52009-05-02 05:32:20 +00003181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003183 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
3185 /* Note: On -EAGAIN error only caller can retry on handle based calls
3186 since file handle passed in no longer valid */
3187
3188 return rc;
3189}
Steve Frenchc52a95542011-02-24 06:16:22 +00003190#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
3192#ifdef CONFIG_CIFS_POSIX
3193
3194/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003195static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3196 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197{
3198 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003199 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3200 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3201 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003202/*
3203 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3204 ace->e_perm, ace->e_tag, ace->e_id);
3205*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
3207 return;
3208}
3209
3210/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003211static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3212 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213{
3214 int size = 0;
3215 int i;
3216 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003217 struct cifs_posix_ace *pACE;
3218 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3219 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
3221 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3222 return -EOPNOTSUPP;
3223
Steve French790fe572007-07-07 19:25:05 +00003224 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 count = le16_to_cpu(cifs_acl->access_entry_count);
3226 pACE = &cifs_acl->ace_array[0];
3227 size = sizeof(struct cifs_posix_acl);
3228 size += sizeof(struct cifs_posix_ace) * count;
3229 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003230 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003231 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3232 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 return -EINVAL;
3234 }
Steve French790fe572007-07-07 19:25:05 +00003235 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 count = le16_to_cpu(cifs_acl->access_entry_count);
3237 size = sizeof(struct cifs_posix_acl);
3238 size += sizeof(struct cifs_posix_ace) * count;
3239/* skip past access ACEs to get to default ACEs */
3240 pACE = &cifs_acl->ace_array[count];
3241 count = le16_to_cpu(cifs_acl->default_entry_count);
3242 size += sizeof(struct cifs_posix_ace) * count;
3243 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003244 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 return -EINVAL;
3246 } else {
3247 /* illegal type */
3248 return -EINVAL;
3249 }
3250
3251 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003252 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003253 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003254 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 return -ERANGE;
3256 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003257 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003258 for (i = 0; i < count ; i++) {
3259 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3260 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 }
3262 }
3263 return size;
3264}
3265
Steve French50c2f752007-07-13 00:33:32 +00003266static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3267 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268{
3269 __u16 rc = 0; /* 0 = ACL converted ok */
3270
Steve Frenchff7feac2005-11-15 16:45:16 -08003271 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3272 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003274 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 /* Probably no need to le convert -1 on any arch but can not hurt */
3276 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003277 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003278 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003279/*
3280 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3281 ace->e_perm, ace->e_tag, ace->e_id);
3282*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 return rc;
3284}
3285
3286/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003287static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3288 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289{
3290 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003291 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3292 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 int count;
3294 int i;
3295
Steve French790fe572007-07-07 19:25:05 +00003296 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 return 0;
3298
3299 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003300 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3301 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003302 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003303 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3304 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return 0;
3306 }
3307 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003308 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003309 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003310 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003311 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003313 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 return 0;
3315 }
Steve French50c2f752007-07-13 00:33:32 +00003316 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3318 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003319 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 /* ACE not converted */
3321 break;
3322 }
3323 }
Steve French790fe572007-07-07 19:25:05 +00003324 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3326 rc += sizeof(struct cifs_posix_acl);
3327 /* BB add check to make sure ACL does not overflow SMB */
3328 }
3329 return rc;
3330}
3331
3332int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003333CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003334 const unsigned char *searchName,
3335 char *acl_inf, const int buflen, const int acl_type,
3336 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337{
3338/* SMB_QUERY_POSIX_ACL */
3339 TRANSACTION2_QPI_REQ *pSMB = NULL;
3340 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3341 int rc = 0;
3342 int bytes_returned;
3343 int name_len;
3344 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003345
Joe Perchesf96637b2013-05-04 22:12:25 -05003346 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347
3348queryAclRetry:
3349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3350 (void **) &pSMBr);
3351 if (rc)
3352 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003353
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3355 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003356 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3357 searchName, PATH_MAX, nls_codepage,
3358 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 name_len++; /* trailing null */
3360 name_len *= 2;
3361 pSMB->FileName[name_len] = 0;
3362 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003363 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 name_len = strnlen(searchName, PATH_MAX);
3365 name_len++; /* trailing null */
3366 strncpy(pSMB->FileName, searchName, name_len);
3367 }
3368
3369 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3370 pSMB->TotalDataCount = 0;
3371 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003372 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 pSMB->MaxDataCount = cpu_to_le16(4000);
3374 pSMB->MaxSetupCount = 0;
3375 pSMB->Reserved = 0;
3376 pSMB->Flags = 0;
3377 pSMB->Timeout = 0;
3378 pSMB->Reserved2 = 0;
3379 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003380 offsetof(struct smb_com_transaction2_qpi_req,
3381 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 pSMB->DataCount = 0;
3383 pSMB->DataOffset = 0;
3384 pSMB->SetupCount = 1;
3385 pSMB->Reserved3 = 0;
3386 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3387 byte_count = params + 1 /* pad */ ;
3388 pSMB->TotalParameterCount = cpu_to_le16(params);
3389 pSMB->ParameterCount = pSMB->TotalParameterCount;
3390 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3391 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003392 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 pSMB->ByteCount = cpu_to_le16(byte_count);
3394
3395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3396 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003397 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003399 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else {
3401 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003402
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003405 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 rc = -EIO; /* bad smb */
3407 else {
3408 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3409 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3410 rc = cifs_copy_posix_acl(acl_inf,
3411 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003412 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 }
3414 }
3415 cifs_buf_release(pSMB);
3416 if (rc == -EAGAIN)
3417 goto queryAclRetry;
3418 return rc;
3419}
3420
3421int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003422CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003423 const unsigned char *fileName,
3424 const char *local_acl, const int buflen,
3425 const int acl_type,
3426 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427{
3428 struct smb_com_transaction2_spi_req *pSMB = NULL;
3429 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3430 char *parm_data;
3431 int name_len;
3432 int rc = 0;
3433 int bytes_returned = 0;
3434 __u16 params, byte_count, data_count, param_offset, offset;
3435
Joe Perchesf96637b2013-05-04 22:12:25 -05003436 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437setAclRetry:
3438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003439 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 if (rc)
3441 return rc;
3442 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3443 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003444 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3445 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 name_len++; /* trailing null */
3447 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003448 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 name_len = strnlen(fileName, PATH_MAX);
3450 name_len++; /* trailing null */
3451 strncpy(pSMB->FileName, fileName, name_len);
3452 }
3453 params = 6 + name_len;
3454 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003455 /* BB find max SMB size from sess */
3456 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 pSMB->MaxSetupCount = 0;
3458 pSMB->Reserved = 0;
3459 pSMB->Flags = 0;
3460 pSMB->Timeout = 0;
3461 pSMB->Reserved2 = 0;
3462 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003463 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 offset = param_offset + params;
3465 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3466 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3467
3468 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003469 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470
Steve French790fe572007-07-07 19:25:05 +00003471 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 rc = -EOPNOTSUPP;
3473 goto setACLerrorExit;
3474 }
3475 pSMB->DataOffset = cpu_to_le16(offset);
3476 pSMB->SetupCount = 1;
3477 pSMB->Reserved3 = 0;
3478 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3479 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3480 byte_count = 3 /* pad */ + params + data_count;
3481 pSMB->DataCount = cpu_to_le16(data_count);
3482 pSMB->TotalDataCount = pSMB->DataCount;
3483 pSMB->ParameterCount = cpu_to_le16(params);
3484 pSMB->TotalParameterCount = pSMB->ParameterCount;
3485 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003486 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 pSMB->ByteCount = cpu_to_le16(byte_count);
3488 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003489 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003490 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003491 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
3493setACLerrorExit:
3494 cifs_buf_release(pSMB);
3495 if (rc == -EAGAIN)
3496 goto setAclRetry;
3497 return rc;
3498}
3499
Steve Frenchf654bac2005-04-28 22:41:04 -07003500/* BB fix tabs in this function FIXME BB */
3501int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003502CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003503 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003504{
Steve French50c2f752007-07-13 00:33:32 +00003505 int rc = 0;
3506 struct smb_t2_qfi_req *pSMB = NULL;
3507 struct smb_t2_qfi_rsp *pSMBr = NULL;
3508 int bytes_returned;
3509 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003510
Joe Perchesf96637b2013-05-04 22:12:25 -05003511 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003512 if (tcon == NULL)
3513 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003514
3515GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003516 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3517 (void **) &pSMBr);
3518 if (rc)
3519 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003520
Steve Frenchad7a2922008-02-07 23:25:02 +00003521 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003522 pSMB->t2.TotalDataCount = 0;
3523 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3524 /* BB find exact max data count below from sess structure BB */
3525 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3526 pSMB->t2.MaxSetupCount = 0;
3527 pSMB->t2.Reserved = 0;
3528 pSMB->t2.Flags = 0;
3529 pSMB->t2.Timeout = 0;
3530 pSMB->t2.Reserved2 = 0;
3531 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3532 Fid) - 4);
3533 pSMB->t2.DataCount = 0;
3534 pSMB->t2.DataOffset = 0;
3535 pSMB->t2.SetupCount = 1;
3536 pSMB->t2.Reserved3 = 0;
3537 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3538 byte_count = params + 1 /* pad */ ;
3539 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3540 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3541 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3542 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003543 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003544 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003545 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003546
Steve French790fe572007-07-07 19:25:05 +00003547 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3548 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3549 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003550 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003551 } else {
3552 /* decode response */
3553 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003554 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003555 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003556 /* If rc should we check for EOPNOSUPP and
3557 disable the srvino flag? or in caller? */
3558 rc = -EIO; /* bad smb */
3559 else {
3560 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3561 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3562 struct file_chattr_info *pfinfo;
3563 /* BB Do we need a cast or hash here ? */
3564 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003565 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003566 rc = -EIO;
3567 goto GetExtAttrOut;
3568 }
3569 pfinfo = (struct file_chattr_info *)
3570 (data_offset + (char *) &pSMBr->hdr.Protocol);
3571 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003572 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003573 }
3574 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003575GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003576 cifs_buf_release(pSMB);
3577 if (rc == -EAGAIN)
3578 goto GetExtAttrRetry;
3579 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003580}
3581
Steve Frenchf654bac2005-04-28 22:41:04 -07003582#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583
Jeff Layton79df1ba2010-12-06 12:52:08 -05003584#ifdef CONFIG_CIFS_ACL
3585/*
3586 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3587 * all NT TRANSACTS that we init here have total parm and data under about 400
3588 * bytes (to fit in small cifs buffer size), which is the case so far, it
3589 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3590 * returned setup area) and MaxParameterCount (returned parms size) must be set
3591 * by caller
3592 */
3593static int
3594smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003595 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003596 void **ret_buf)
3597{
3598 int rc;
3599 __u32 temp_offset;
3600 struct smb_com_ntransact_req *pSMB;
3601
3602 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3603 (void **)&pSMB);
3604 if (rc)
3605 return rc;
3606 *ret_buf = (void *)pSMB;
3607 pSMB->Reserved = 0;
3608 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3609 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003610 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003611 pSMB->ParameterCount = pSMB->TotalParameterCount;
3612 pSMB->DataCount = pSMB->TotalDataCount;
3613 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3614 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3615 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3616 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3617 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3618 pSMB->SubCommand = cpu_to_le16(sub_command);
3619 return 0;
3620}
3621
3622static int
3623validate_ntransact(char *buf, char **ppparm, char **ppdata,
3624 __u32 *pparmlen, __u32 *pdatalen)
3625{
3626 char *end_of_smb;
3627 __u32 data_count, data_offset, parm_count, parm_offset;
3628 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003629 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003630
3631 *pdatalen = 0;
3632 *pparmlen = 0;
3633
3634 if (buf == NULL)
3635 return -EINVAL;
3636
3637 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3638
Jeff Layton820a8032011-05-04 08:05:26 -04003639 bcc = get_bcc(&pSMBr->hdr);
3640 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003641 (char *)&pSMBr->ByteCount;
3642
3643 data_offset = le32_to_cpu(pSMBr->DataOffset);
3644 data_count = le32_to_cpu(pSMBr->DataCount);
3645 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3646 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3647
3648 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3649 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3650
3651 /* should we also check that parm and data areas do not overlap? */
3652 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003653 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003654 return -EINVAL;
3655 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003656 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003657 return -EINVAL;
3658 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003659 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003660 return -EINVAL;
3661 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003662 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3663 *ppdata, data_count, (data_count + *ppdata),
3664 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003665 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003666 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003667 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003668 return -EINVAL;
3669 }
3670 *pdatalen = data_count;
3671 *pparmlen = parm_count;
3672 return 0;
3673}
3674
Steve French0a4b92c2006-01-12 15:44:21 -08003675/* Get Security Descriptor (by handle) from remote server for a file or dir */
3676int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003677CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003678 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003679{
3680 int rc = 0;
3681 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003682 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003683 struct kvec iov[1];
3684
Joe Perchesf96637b2013-05-04 22:12:25 -05003685 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003686
Steve French630f3f0c2007-10-25 21:17:17 +00003687 *pbuflen = 0;
3688 *acl_inf = NULL;
3689
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003690 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003691 8 /* parm len */, tcon, (void **) &pSMB);
3692 if (rc)
3693 return rc;
3694
3695 pSMB->MaxParameterCount = cpu_to_le32(4);
3696 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3697 pSMB->MaxSetupCount = 0;
3698 pSMB->Fid = fid; /* file handle always le */
3699 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3700 CIFS_ACL_DACL);
3701 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003702 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003703 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003704 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003705
Steve Frencha761ac52007-10-18 21:45:27 +00003706 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003707 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003708 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003709 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003710 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003711 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003712 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003713 __u32 parm_len;
3714 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003715 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003716 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003717
3718/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003719 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003720 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003721 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003722 goto qsec_out;
3723 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3724
Joe Perchesf96637b2013-05-04 22:12:25 -05003725 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3726 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003727
3728 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3729 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003730 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003731 goto qsec_out;
3732 }
3733
3734/* BB check that data area is minimum length and as big as acl_len */
3735
Steve Frenchaf6f4612007-10-16 18:40:37 +00003736 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003737 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003738 cifs_dbg(VFS, "acl length %d does not match %d\n",
3739 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003740 if (*pbuflen > acl_len)
3741 *pbuflen = acl_len;
3742 }
Steve French0a4b92c2006-01-12 15:44:21 -08003743
Steve French630f3f0c2007-10-25 21:17:17 +00003744 /* check if buffer is big enough for the acl
3745 header followed by the smallest SID */
3746 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3747 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003748 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003749 rc = -EINVAL;
3750 *pbuflen = 0;
3751 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003752 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003753 if (*acl_inf == NULL) {
3754 *pbuflen = 0;
3755 rc = -ENOMEM;
3756 }
Steve French630f3f0c2007-10-25 21:17:17 +00003757 }
Steve French0a4b92c2006-01-12 15:44:21 -08003758 }
3759qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003760 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003761 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003762 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003763 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003764/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003765 return rc;
3766}
Steve French97837582007-12-31 07:47:21 +00003767
3768int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003769CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003770 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003771{
3772 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3773 int rc = 0;
3774 int bytes_returned = 0;
3775 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003776 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003777
3778setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003779 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003780 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003781 return rc;
Steve French97837582007-12-31 07:47:21 +00003782
3783 pSMB->MaxSetupCount = 0;
3784 pSMB->Reserved = 0;
3785
3786 param_count = 8;
3787 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3788 data_count = acllen;
3789 data_offset = param_offset + param_count;
3790 byte_count = 3 /* pad */ + param_count;
3791
3792 pSMB->DataCount = cpu_to_le32(data_count);
3793 pSMB->TotalDataCount = pSMB->DataCount;
3794 pSMB->MaxParameterCount = cpu_to_le32(4);
3795 pSMB->MaxDataCount = cpu_to_le32(16384);
3796 pSMB->ParameterCount = cpu_to_le32(param_count);
3797 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3798 pSMB->TotalParameterCount = pSMB->ParameterCount;
3799 pSMB->DataOffset = cpu_to_le32(data_offset);
3800 pSMB->SetupCount = 0;
3801 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3802 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3803
3804 pSMB->Fid = fid; /* file handle always le */
3805 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003806 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003807
3808 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003809 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3810 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003811 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003812 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003813 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003814
3815 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3816 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3817
Joe Perchesf96637b2013-05-04 22:12:25 -05003818 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
3819 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003820 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003821 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00003822 cifs_buf_release(pSMB);
3823
3824 if (rc == -EAGAIN)
3825 goto setCifsAclRetry;
3826
3827 return (rc);
3828}
3829
Jeff Layton79df1ba2010-12-06 12:52:08 -05003830#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003831
Steve French6b8edfe2005-08-23 20:26:03 -07003832/* Legacy Query Path Information call for lookup to old servers such
3833 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003834int
3835SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3836 const char *search_name, FILE_ALL_INFO *data,
3837 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003838{
Steve Frenchad7a2922008-02-07 23:25:02 +00003839 QUERY_INFORMATION_REQ *pSMB;
3840 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003841 int rc = 0;
3842 int bytes_returned;
3843 int name_len;
3844
Joe Perchesf96637b2013-05-04 22:12:25 -05003845 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003846QInfRetry:
3847 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003848 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003849 if (rc)
3850 return rc;
3851
3852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3853 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003854 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003855 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003856 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003857 name_len++; /* trailing null */
3858 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003859 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003860 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003861 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003862 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003863 }
3864 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003865 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003866 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003867 pSMB->ByteCount = cpu_to_le16(name_len);
3868
3869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003871 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003872 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003873 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003874 struct timespec ts;
3875 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003876
3877 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003878 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003879 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003880 ts.tv_nsec = 0;
3881 ts.tv_sec = time;
3882 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003883 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3884 data->LastWriteTime = data->ChangeTime;
3885 data->LastAccessTime = 0;
3886 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003887 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003888 data->EndOfFile = data->AllocationSize;
3889 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003890 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003891 } else
3892 rc = -EIO; /* bad buffer passed in */
3893
3894 cifs_buf_release(pSMB);
3895
3896 if (rc == -EAGAIN)
3897 goto QInfRetry;
3898
3899 return rc;
3900}
3901
Jeff Laytonbcd53572010-02-12 07:44:16 -05003902int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003903CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003904 u16 netfid, FILE_ALL_INFO *pFindData)
3905{
3906 struct smb_t2_qfi_req *pSMB = NULL;
3907 struct smb_t2_qfi_rsp *pSMBr = NULL;
3908 int rc = 0;
3909 int bytes_returned;
3910 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003911
Jeff Laytonbcd53572010-02-12 07:44:16 -05003912QFileInfoRetry:
3913 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3914 (void **) &pSMBr);
3915 if (rc)
3916 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003917
Jeff Laytonbcd53572010-02-12 07:44:16 -05003918 params = 2 /* level */ + 2 /* fid */;
3919 pSMB->t2.TotalDataCount = 0;
3920 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3921 /* BB find exact max data count below from sess structure BB */
3922 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3923 pSMB->t2.MaxSetupCount = 0;
3924 pSMB->t2.Reserved = 0;
3925 pSMB->t2.Flags = 0;
3926 pSMB->t2.Timeout = 0;
3927 pSMB->t2.Reserved2 = 0;
3928 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3929 Fid) - 4);
3930 pSMB->t2.DataCount = 0;
3931 pSMB->t2.DataOffset = 0;
3932 pSMB->t2.SetupCount = 1;
3933 pSMB->t2.Reserved3 = 0;
3934 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3935 byte_count = params + 1 /* pad */ ;
3936 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3937 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3938 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3939 pSMB->Pad = 0;
3940 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003941 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003942
3943 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3945 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003946 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003947 } else { /* decode response */
3948 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3949
3950 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3951 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003952 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003953 rc = -EIO; /* bad smb */
3954 else if (pFindData) {
3955 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3956 memcpy((char *) pFindData,
3957 (char *) &pSMBr->hdr.Protocol +
3958 data_offset, sizeof(FILE_ALL_INFO));
3959 } else
3960 rc = -ENOMEM;
3961 }
3962 cifs_buf_release(pSMB);
3963 if (rc == -EAGAIN)
3964 goto QFileInfoRetry;
3965
3966 return rc;
3967}
Steve French6b8edfe2005-08-23 20:26:03 -07003968
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003970CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003971 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003972 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003973 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003975 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 TRANSACTION2_QPI_REQ *pSMB = NULL;
3977 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3978 int rc = 0;
3979 int bytes_returned;
3980 int name_len;
3981 __u16 params, byte_count;
3982
Joe Perchesf96637b2013-05-04 22:12:25 -05003983 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984QPathInfoRetry:
3985 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3986 (void **) &pSMBr);
3987 if (rc)
3988 return rc;
3989
3990 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3991 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003992 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003993 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 name_len++; /* trailing null */
3995 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003996 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003997 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003999 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 }
4001
Steve French50c2f752007-07-13 00:33:32 +00004002 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 pSMB->TotalDataCount = 0;
4004 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004005 /* BB find exact max SMB PDU from sess structure BB */
4006 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 pSMB->MaxSetupCount = 0;
4008 pSMB->Reserved = 0;
4009 pSMB->Flags = 0;
4010 pSMB->Timeout = 0;
4011 pSMB->Reserved2 = 0;
4012 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004013 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 pSMB->DataCount = 0;
4015 pSMB->DataOffset = 0;
4016 pSMB->SetupCount = 1;
4017 pSMB->Reserved3 = 0;
4018 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4019 byte_count = params + 1 /* pad */ ;
4020 pSMB->TotalParameterCount = cpu_to_le16(params);
4021 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004022 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004023 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4024 else
4025 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004027 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 pSMB->ByteCount = cpu_to_le16(byte_count);
4029
4030 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4031 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4032 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004033 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 } else { /* decode response */
4035 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4036
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004037 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4038 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004039 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004041 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004042 rc = -EIO; /* 24 or 26 expected but we do not read
4043 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004044 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004045 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004047
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004048 /*
4049 * On legacy responses we do not read the last field,
4050 * EAsize, fortunately since it varies by subdialect and
4051 * also note it differs on Set vs Get, ie two bytes or 4
4052 * bytes depending but we don't care here.
4053 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004054 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004055 size = sizeof(FILE_INFO_STANDARD);
4056 else
4057 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004058 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004059 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 } else
4061 rc = -ENOMEM;
4062 }
4063 cifs_buf_release(pSMB);
4064 if (rc == -EAGAIN)
4065 goto QPathInfoRetry;
4066
4067 return rc;
4068}
4069
4070int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004071CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004072 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4073{
4074 struct smb_t2_qfi_req *pSMB = NULL;
4075 struct smb_t2_qfi_rsp *pSMBr = NULL;
4076 int rc = 0;
4077 int bytes_returned;
4078 __u16 params, byte_count;
4079
4080UnixQFileInfoRetry:
4081 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4082 (void **) &pSMBr);
4083 if (rc)
4084 return rc;
4085
4086 params = 2 /* level */ + 2 /* fid */;
4087 pSMB->t2.TotalDataCount = 0;
4088 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4089 /* BB find exact max data count below from sess structure BB */
4090 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4091 pSMB->t2.MaxSetupCount = 0;
4092 pSMB->t2.Reserved = 0;
4093 pSMB->t2.Flags = 0;
4094 pSMB->t2.Timeout = 0;
4095 pSMB->t2.Reserved2 = 0;
4096 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4097 Fid) - 4);
4098 pSMB->t2.DataCount = 0;
4099 pSMB->t2.DataOffset = 0;
4100 pSMB->t2.SetupCount = 1;
4101 pSMB->t2.Reserved3 = 0;
4102 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4103 byte_count = params + 1 /* pad */ ;
4104 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4105 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4106 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4107 pSMB->Pad = 0;
4108 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004109 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004110
4111 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4112 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4113 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004114 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004115 } else { /* decode response */
4116 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4117
Jeff Layton820a8032011-05-04 08:05:26 -04004118 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004119 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 -05004120 rc = -EIO; /* bad smb */
4121 } else {
4122 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4123 memcpy((char *) pFindData,
4124 (char *) &pSMBr->hdr.Protocol +
4125 data_offset,
4126 sizeof(FILE_UNIX_BASIC_INFO));
4127 }
4128 }
4129
4130 cifs_buf_release(pSMB);
4131 if (rc == -EAGAIN)
4132 goto UnixQFileInfoRetry;
4133
4134 return rc;
4135}
4136
4137int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004138CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004140 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004141 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142{
4143/* SMB_QUERY_FILE_UNIX_BASIC */
4144 TRANSACTION2_QPI_REQ *pSMB = NULL;
4145 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4146 int rc = 0;
4147 int bytes_returned = 0;
4148 int name_len;
4149 __u16 params, byte_count;
4150
Joe Perchesf96637b2013-05-04 22:12:25 -05004151 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152UnixQPathInfoRetry:
4153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4154 (void **) &pSMBr);
4155 if (rc)
4156 return rc;
4157
4158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4159 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004160 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4161 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 name_len++; /* trailing null */
4163 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004164 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 name_len = strnlen(searchName, PATH_MAX);
4166 name_len++; /* trailing null */
4167 strncpy(pSMB->FileName, searchName, name_len);
4168 }
4169
Steve French50c2f752007-07-13 00:33:32 +00004170 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 pSMB->TotalDataCount = 0;
4172 pSMB->MaxParameterCount = cpu_to_le16(2);
4173 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004174 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 pSMB->MaxSetupCount = 0;
4176 pSMB->Reserved = 0;
4177 pSMB->Flags = 0;
4178 pSMB->Timeout = 0;
4179 pSMB->Reserved2 = 0;
4180 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004181 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 pSMB->DataCount = 0;
4183 pSMB->DataOffset = 0;
4184 pSMB->SetupCount = 1;
4185 pSMB->Reserved3 = 0;
4186 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4187 byte_count = params + 1 /* pad */ ;
4188 pSMB->TotalParameterCount = cpu_to_le16(params);
4189 pSMB->ParameterCount = pSMB->TotalParameterCount;
4190 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4191 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004192 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 pSMB->ByteCount = cpu_to_le16(byte_count);
4194
4195 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4196 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4197 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004198 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 } else { /* decode response */
4200 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4201
Jeff Layton820a8032011-05-04 08:05:26 -04004202 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004203 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 -07004204 rc = -EIO; /* bad smb */
4205 } else {
4206 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4207 memcpy((char *) pFindData,
4208 (char *) &pSMBr->hdr.Protocol +
4209 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004210 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 }
4212 }
4213 cifs_buf_release(pSMB);
4214 if (rc == -EAGAIN)
4215 goto UnixQPathInfoRetry;
4216
4217 return rc;
4218}
4219
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220/* xid, tcon, searchName and codepage are input parms, rest are returned */
4221int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004222CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004223 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004224 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004225 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226{
4227/* level 257 SMB_ */
4228 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4229 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004230 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 int rc = 0;
4232 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004233 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004235 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
Joe Perchesf96637b2013-05-04 22:12:25 -05004237 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238
4239findFirstRetry:
4240 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4241 (void **) &pSMBr);
4242 if (rc)
4243 return rc;
4244
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004245 nls_codepage = cifs_sb->local_nls;
4246 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4247
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4249 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004250 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4251 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004252 /* We can not add the asterik earlier in case
4253 it got remapped to 0xF03A as if it were part of the
4254 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004256 if (msearch) {
4257 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4258 pSMB->FileName[name_len+1] = 0;
4259 pSMB->FileName[name_len+2] = '*';
4260 pSMB->FileName[name_len+3] = 0;
4261 name_len += 4; /* now the trailing null */
4262 /* null terminate just in case */
4263 pSMB->FileName[name_len] = 0;
4264 pSMB->FileName[name_len+1] = 0;
4265 name_len += 2;
4266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 } else { /* BB add check for overrun of SMB buf BB */
4268 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004270 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 free buffer exit; BB */
4272 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004273 if (msearch) {
4274 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4275 pSMB->FileName[name_len+1] = '*';
4276 pSMB->FileName[name_len+2] = 0;
4277 name_len += 3;
4278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 }
4280
4281 params = 12 + name_len /* includes null */ ;
4282 pSMB->TotalDataCount = 0; /* no EAs */
4283 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004284 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 pSMB->MaxSetupCount = 0;
4286 pSMB->Reserved = 0;
4287 pSMB->Flags = 0;
4288 pSMB->Timeout = 0;
4289 pSMB->Reserved2 = 0;
4290 byte_count = params + 1 /* pad */ ;
4291 pSMB->TotalParameterCount = cpu_to_le16(params);
4292 pSMB->ParameterCount = pSMB->TotalParameterCount;
4293 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004294 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4295 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 pSMB->DataCount = 0;
4297 pSMB->DataOffset = 0;
4298 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4299 pSMB->Reserved3 = 0;
4300 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4301 pSMB->SearchAttributes =
4302 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4303 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004304 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004305 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4307
4308 /* BB what should we set StorageType to? Does it matter? BB */
4309 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004310 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 pSMB->ByteCount = cpu_to_le16(byte_count);
4312
4313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4314 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004315 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316
Steve French88274812006-03-09 22:21:45 +00004317 if (rc) {/* BB add logic to retry regular search if Unix search
4318 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004320 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004321
Steve French88274812006-03-09 22:21:45 +00004322 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323
4324 /* BB eventually could optimize out free and realloc of buf */
4325 /* for this case */
4326 if (rc == -EAGAIN)
4327 goto findFirstRetry;
4328 } else { /* decode response */
4329 /* BB remember to free buffer if error BB */
4330 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004331 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004332 unsigned int lnoff;
4333
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004335 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 else
Steve French4b18f2a2008-04-29 00:06:05 +00004337 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
4339 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004340 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004341 psrch_inf->srch_entries_start =
4342 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4345 le16_to_cpu(pSMBr->t2.ParameterOffset));
4346
Steve French790fe572007-07-07 19:25:05 +00004347 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004348 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 else
Steve French4b18f2a2008-04-29 00:06:05 +00004350 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
Steve French50c2f752007-07-13 00:33:32 +00004352 psrch_inf->entries_in_buffer =
4353 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004354 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004356 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004357 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004358 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004359 psrch_inf->last_entry = NULL;
4360 return rc;
4361 }
4362
Steve French0752f152008-10-07 20:03:33 +00004363 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004364 lnoff;
4365
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004366 if (pnetfid)
4367 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 } else {
4369 cifs_buf_release(pSMB);
4370 }
4371 }
4372
4373 return rc;
4374}
4375
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004376int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4377 __u16 searchHandle, __u16 search_flags,
4378 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379{
4380 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4381 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004382 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 char *response_data;
4384 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004385 int bytes_returned;
4386 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 __u16 params, byte_count;
4388
Joe Perchesf96637b2013-05-04 22:12:25 -05004389 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390
Steve French4b18f2a2008-04-29 00:06:05 +00004391 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 return -ENOENT;
4393
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4398
Steve French50c2f752007-07-13 00:33:32 +00004399 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 byte_count = 0;
4401 pSMB->TotalDataCount = 0; /* no EAs */
4402 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004403 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 pSMB->MaxSetupCount = 0;
4405 pSMB->Reserved = 0;
4406 pSMB->Flags = 0;
4407 pSMB->Timeout = 0;
4408 pSMB->Reserved2 = 0;
4409 pSMB->ParameterOffset = cpu_to_le16(
4410 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4411 pSMB->DataCount = 0;
4412 pSMB->DataOffset = 0;
4413 pSMB->SetupCount = 1;
4414 pSMB->Reserved3 = 0;
4415 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4416 pSMB->SearchHandle = searchHandle; /* always kept as le */
4417 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004418 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4420 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004421 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
4423 name_len = psrch_inf->resume_name_len;
4424 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004425 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4427 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004428 /* 14 byte parm len above enough for 2 byte null terminator */
4429 pSMB->ResumeFileName[name_len] = 0;
4430 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 } else {
4432 rc = -EINVAL;
4433 goto FNext2_err_exit;
4434 }
4435 byte_count = params + 1 /* pad */ ;
4436 pSMB->TotalParameterCount = cpu_to_le16(params);
4437 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004438 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004440
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004443 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 if (rc) {
4445 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004446 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004447 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004448 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004450 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 } else { /* decode response */
4452 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004453
Steve French790fe572007-07-07 19:25:05 +00004454 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004455 unsigned int lnoff;
4456
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 /* BB fixme add lock for file (srch_info) struct here */
4458 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004459 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 else
Steve French4b18f2a2008-04-29 00:06:05 +00004461 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 response_data = (char *) &pSMBr->hdr.Protocol +
4463 le16_to_cpu(pSMBr->t2.ParameterOffset);
4464 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4465 response_data = (char *)&pSMBr->hdr.Protocol +
4466 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004467 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004468 cifs_small_buf_release(
4469 psrch_inf->ntwrk_buf_start);
4470 else
4471 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 psrch_inf->srch_entries_start = response_data;
4473 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004474 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004475 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004476 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 else
Steve French4b18f2a2008-04-29 00:06:05 +00004478 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004479 psrch_inf->entries_in_buffer =
4480 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 psrch_inf->index_of_last_entry +=
4482 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004483 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004484 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004485 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004486 psrch_inf->last_entry = NULL;
4487 return rc;
4488 } else
4489 psrch_inf->last_entry =
4490 psrch_inf->srch_entries_start + lnoff;
4491
Joe Perchesf96637b2013-05-04 22:12:25 -05004492/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4493 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
4495 /* BB fixme add unlock here */
4496 }
4497
4498 }
4499
4500 /* BB On error, should we leave previous search buf (and count and
4501 last entry fields) intact or free the previous one? */
4502
4503 /* Note: On -EAGAIN error only caller can retry on handle based calls
4504 since file handle passed in no longer valid */
4505FNext2_err_exit:
4506 if (rc != 0)
4507 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 return rc;
4509}
4510
4511int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004512CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004513 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514{
4515 int rc = 0;
4516 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517
Joe Perchesf96637b2013-05-04 22:12:25 -05004518 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4520
4521 /* no sense returning error if session restarted
4522 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004523 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 return 0;
4525 if (rc)
4526 return rc;
4527
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 pSMB->FileID = searchHandle;
4529 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004530 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004531 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004532 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004533
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004534 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535
4536 /* Since session is dead, search handle closed on server already */
4537 if (rc == -EAGAIN)
4538 rc = 0;
4539
4540 return rc;
4541}
4542
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004544CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004545 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004546 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547{
4548 int rc = 0;
4549 TRANSACTION2_QPI_REQ *pSMB = NULL;
4550 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4551 int name_len, bytes_returned;
4552 __u16 params, byte_count;
4553
Joe Perchesf96637b2013-05-04 22:12:25 -05004554 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004555 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004556 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557
4558GetInodeNumberRetry:
4559 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004560 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 if (rc)
4562 return rc;
4563
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4565 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004566 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004567 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004568 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 name_len++; /* trailing null */
4570 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004571 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004572 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004574 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 }
4576
4577 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4578 pSMB->TotalDataCount = 0;
4579 pSMB->MaxParameterCount = cpu_to_le16(2);
4580 /* BB find exact max data count below from sess structure BB */
4581 pSMB->MaxDataCount = cpu_to_le16(4000);
4582 pSMB->MaxSetupCount = 0;
4583 pSMB->Reserved = 0;
4584 pSMB->Flags = 0;
4585 pSMB->Timeout = 0;
4586 pSMB->Reserved2 = 0;
4587 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004588 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 pSMB->DataCount = 0;
4590 pSMB->DataOffset = 0;
4591 pSMB->SetupCount = 1;
4592 pSMB->Reserved3 = 0;
4593 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4594 byte_count = params + 1 /* pad */ ;
4595 pSMB->TotalParameterCount = cpu_to_le16(params);
4596 pSMB->ParameterCount = pSMB->TotalParameterCount;
4597 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4598 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004599 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 pSMB->ByteCount = cpu_to_le16(byte_count);
4601
4602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4604 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004605 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 } else {
4607 /* decode response */
4608 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004610 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 /* If rc should we check for EOPNOSUPP and
4612 disable the srvino flag? or in caller? */
4613 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004614 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4616 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004617 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004619 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004620 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 rc = -EIO;
4622 goto GetInodeNumOut;
4623 }
4624 pfinfo = (struct file_internal_info *)
4625 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004626 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 }
4628 }
4629GetInodeNumOut:
4630 cifs_buf_release(pSMB);
4631 if (rc == -EAGAIN)
4632 goto GetInodeNumberRetry;
4633 return rc;
4634}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635
Igor Mammedovfec45852008-05-16 13:06:30 +04004636/* parses DFS refferal V3 structure
4637 * caller is responsible for freeing target_nodes
4638 * returns:
4639 * on success - 0
4640 * on failure - errno
4641 */
4642static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004643parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004644 unsigned int *num_of_nodes,
4645 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004646 const struct nls_table *nls_codepage, int remap,
4647 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004648{
4649 int i, rc = 0;
4650 char *data_end;
4651 bool is_unicode;
4652 struct dfs_referral_level_3 *ref;
4653
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004654 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4655 is_unicode = true;
4656 else
4657 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004658 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4659
4660 if (*num_of_nodes < 1) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004661 cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4662 *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004663 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004664 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004665 }
4666
4667 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004668 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004669 cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4670 le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004671 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004672 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004673 }
4674
4675 /* get the upper boundary of the resp buffer */
4676 data_end = (char *)(&(pSMBr->PathConsumed)) +
4677 le16_to_cpu(pSMBr->t2.DataCount);
4678
Joe Perchesf96637b2013-05-04 22:12:25 -05004679 cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4680 *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004681
Joe Perchesf96637b2013-05-04 22:12:25 -05004682 *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4683 GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +04004684 if (*target_nodes == NULL) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004686 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004687 }
4688
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004689 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004690 for (i = 0; i < *num_of_nodes; i++) {
4691 char *temp;
4692 int max_len;
4693 struct dfs_info3_param *node = (*target_nodes)+i;
4694
Steve French0e0d2cf2009-05-01 05:27:32 +00004695 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004696 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004697 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4698 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004699 if (tmp == NULL) {
4700 rc = -ENOMEM;
4701 goto parse_DFS_referrals_exit;
4702 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004703 cifsConvertToUTF16((__le16 *) tmp, searchName,
4704 PATH_MAX, nls_codepage, remap);
4705 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004706 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004707 nls_codepage);
4708 kfree(tmp);
4709 } else
4710 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4711
Igor Mammedovfec45852008-05-16 13:06:30 +04004712 node->server_type = le16_to_cpu(ref->ServerType);
4713 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4714
4715 /* copy DfsPath */
4716 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4717 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004718 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4719 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004720 if (!node->path_name) {
4721 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004722 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004723 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004724
4725 /* copy link target UNC */
4726 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4727 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004728 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4729 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004730 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004731 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004732 goto parse_DFS_referrals_exit;
4733 }
4734
4735 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004736 }
4737
Steve Frencha1fe78f2008-05-16 18:48:38 +00004738parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004739 if (rc) {
4740 free_dfs_info_array(*target_nodes, *num_of_nodes);
4741 *target_nodes = NULL;
4742 *num_of_nodes = 0;
4743 }
4744 return rc;
4745}
4746
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004748CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004749 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004750 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004751 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752{
4753/* TRANS2_GET_DFS_REFERRAL */
4754 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4755 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 int rc = 0;
4757 int bytes_returned;
4758 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004760 *num_of_nodes = 0;
4761 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Joe Perchesf96637b2013-05-04 22:12:25 -05004763 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 if (ses == NULL)
4765 return -ENODEV;
4766getDFSRetry:
4767 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4768 (void **) &pSMBr);
4769 if (rc)
4770 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004771
4772 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004773 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004774 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 pSMB->hdr.Tid = ses->ipc_tid;
4776 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004777 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004779 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781
4782 if (ses->capabilities & CAP_UNICODE) {
4783 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4784 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004785 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004786 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004787 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 name_len++; /* trailing null */
4789 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004790 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004791 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004793 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 }
4795
Steve French790fe572007-07-07 19:25:05 +00004796 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004797 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004798 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4799 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4800 }
4801
Steve French50c2f752007-07-13 00:33:32 +00004802 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004803
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 params = 2 /* level */ + name_len /*includes null */ ;
4805 pSMB->TotalDataCount = 0;
4806 pSMB->DataCount = 0;
4807 pSMB->DataOffset = 0;
4808 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004809 /* BB find exact max SMB PDU from sess structure BB */
4810 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 pSMB->MaxSetupCount = 0;
4812 pSMB->Reserved = 0;
4813 pSMB->Flags = 0;
4814 pSMB->Timeout = 0;
4815 pSMB->Reserved2 = 0;
4816 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004817 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 pSMB->SetupCount = 1;
4819 pSMB->Reserved3 = 0;
4820 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4821 byte_count = params + 3 /* pad */ ;
4822 pSMB->ParameterCount = cpu_to_le16(params);
4823 pSMB->TotalParameterCount = pSMB->ParameterCount;
4824 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004825 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 pSMB->ByteCount = cpu_to_le16(byte_count);
4827
4828 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4830 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004831 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004832 goto GetDFSRefExit;
4833 }
4834 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004836 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004837 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004838 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004839 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004841
Joe Perchesf96637b2013-05-04 22:12:25 -05004842 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4843 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004844
4845 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004846 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004847 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004848 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004849
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004851 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
4853 if (rc == -EAGAIN)
4854 goto getDFSRetry;
4855
4856 return rc;
4857}
4858
Steve French20962432005-09-21 22:05:57 -07004859/* Query File System Info such as free space to old servers such as Win 9x */
4860int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004861SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4862 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004863{
4864/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4865 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4866 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4867 FILE_SYSTEM_ALLOC_INFO *response_data;
4868 int rc = 0;
4869 int bytes_returned = 0;
4870 __u16 params, byte_count;
4871
Joe Perchesf96637b2013-05-04 22:12:25 -05004872 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004873oldQFSInfoRetry:
4874 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4875 (void **) &pSMBr);
4876 if (rc)
4877 return rc;
Steve French20962432005-09-21 22:05:57 -07004878
4879 params = 2; /* level */
4880 pSMB->TotalDataCount = 0;
4881 pSMB->MaxParameterCount = cpu_to_le16(2);
4882 pSMB->MaxDataCount = cpu_to_le16(1000);
4883 pSMB->MaxSetupCount = 0;
4884 pSMB->Reserved = 0;
4885 pSMB->Flags = 0;
4886 pSMB->Timeout = 0;
4887 pSMB->Reserved2 = 0;
4888 byte_count = params + 1 /* pad */ ;
4889 pSMB->TotalParameterCount = cpu_to_le16(params);
4890 pSMB->ParameterCount = pSMB->TotalParameterCount;
4891 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4892 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4893 pSMB->DataCount = 0;
4894 pSMB->DataOffset = 0;
4895 pSMB->SetupCount = 1;
4896 pSMB->Reserved3 = 0;
4897 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4898 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004899 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004900 pSMB->ByteCount = cpu_to_le16(byte_count);
4901
4902 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4903 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4904 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004905 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004906 } else { /* decode response */
4907 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4908
Jeff Layton820a8032011-05-04 08:05:26 -04004909 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004910 rc = -EIO; /* bad smb */
4911 else {
4912 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004913 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004914 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004915
Steve French50c2f752007-07-13 00:33:32 +00004916 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004917 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4918 FSData->f_bsize =
4919 le16_to_cpu(response_data->BytesPerSector) *
4920 le32_to_cpu(response_data->
4921 SectorsPerAllocationUnit);
4922 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004923 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004924 FSData->f_bfree = FSData->f_bavail =
4925 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05004926 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
4927 (unsigned long long)FSData->f_blocks,
4928 (unsigned long long)FSData->f_bfree,
4929 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004930 }
4931 }
4932 cifs_buf_release(pSMB);
4933
4934 if (rc == -EAGAIN)
4935 goto oldQFSInfoRetry;
4936
4937 return rc;
4938}
4939
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004941CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4942 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943{
4944/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4945 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4946 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4947 FILE_SYSTEM_INFO *response_data;
4948 int rc = 0;
4949 int bytes_returned = 0;
4950 __u16 params, byte_count;
4951
Joe Perchesf96637b2013-05-04 22:12:25 -05004952 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953QFSInfoRetry:
4954 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4955 (void **) &pSMBr);
4956 if (rc)
4957 return rc;
4958
4959 params = 2; /* level */
4960 pSMB->TotalDataCount = 0;
4961 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004962 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 pSMB->MaxSetupCount = 0;
4964 pSMB->Reserved = 0;
4965 pSMB->Flags = 0;
4966 pSMB->Timeout = 0;
4967 pSMB->Reserved2 = 0;
4968 byte_count = params + 1 /* pad */ ;
4969 pSMB->TotalParameterCount = cpu_to_le16(params);
4970 pSMB->ParameterCount = pSMB->TotalParameterCount;
4971 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004972 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 pSMB->DataCount = 0;
4974 pSMB->DataOffset = 0;
4975 pSMB->SetupCount = 1;
4976 pSMB->Reserved3 = 0;
4977 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4978 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004979 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 pSMB->ByteCount = cpu_to_le16(byte_count);
4981
4982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4984 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004985 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004987 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988
Jeff Layton820a8032011-05-04 08:05:26 -04004989 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 rc = -EIO; /* bad smb */
4991 else {
4992 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993
4994 response_data =
4995 (FILE_SYSTEM_INFO
4996 *) (((char *) &pSMBr->hdr.Protocol) +
4997 data_offset);
4998 FSData->f_bsize =
4999 le32_to_cpu(response_data->BytesPerSector) *
5000 le32_to_cpu(response_data->
5001 SectorsPerAllocationUnit);
5002 FSData->f_blocks =
5003 le64_to_cpu(response_data->TotalAllocationUnits);
5004 FSData->f_bfree = FSData->f_bavail =
5005 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005006 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5007 (unsigned long long)FSData->f_blocks,
5008 (unsigned long long)FSData->f_bfree,
5009 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 }
5011 }
5012 cifs_buf_release(pSMB);
5013
5014 if (rc == -EAGAIN)
5015 goto QFSInfoRetry;
5016
5017 return rc;
5018}
5019
5020int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005021CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022{
5023/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5024 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5025 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5026 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5027 int rc = 0;
5028 int bytes_returned = 0;
5029 __u16 params, byte_count;
5030
Joe Perchesf96637b2013-05-04 22:12:25 -05005031 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032QFSAttributeRetry:
5033 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5034 (void **) &pSMBr);
5035 if (rc)
5036 return rc;
5037
5038 params = 2; /* level */
5039 pSMB->TotalDataCount = 0;
5040 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005041 /* BB find exact max SMB PDU from sess structure BB */
5042 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 pSMB->MaxSetupCount = 0;
5044 pSMB->Reserved = 0;
5045 pSMB->Flags = 0;
5046 pSMB->Timeout = 0;
5047 pSMB->Reserved2 = 0;
5048 byte_count = params + 1 /* pad */ ;
5049 pSMB->TotalParameterCount = cpu_to_le16(params);
5050 pSMB->ParameterCount = pSMB->TotalParameterCount;
5051 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005052 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 pSMB->DataCount = 0;
5054 pSMB->DataOffset = 0;
5055 pSMB->SetupCount = 1;
5056 pSMB->Reserved3 = 0;
5057 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5058 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005059 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 pSMB->ByteCount = cpu_to_le16(byte_count);
5061
5062 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5063 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5064 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005065 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 } else { /* decode response */
5067 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5068
Jeff Layton820a8032011-05-04 08:05:26 -04005069 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005070 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 rc = -EIO; /* bad smb */
5072 } else {
5073 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5074 response_data =
5075 (FILE_SYSTEM_ATTRIBUTE_INFO
5076 *) (((char *) &pSMBr->hdr.Protocol) +
5077 data_offset);
5078 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005079 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 }
5081 }
5082 cifs_buf_release(pSMB);
5083
5084 if (rc == -EAGAIN)
5085 goto QFSAttributeRetry;
5086
5087 return rc;
5088}
5089
5090int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005091CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092{
5093/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5094 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5095 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5096 FILE_SYSTEM_DEVICE_INFO *response_data;
5097 int rc = 0;
5098 int bytes_returned = 0;
5099 __u16 params, byte_count;
5100
Joe Perchesf96637b2013-05-04 22:12:25 -05005101 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102QFSDeviceRetry:
5103 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5104 (void **) &pSMBr);
5105 if (rc)
5106 return rc;
5107
5108 params = 2; /* level */
5109 pSMB->TotalDataCount = 0;
5110 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005111 /* BB find exact max SMB PDU from sess structure BB */
5112 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 pSMB->MaxSetupCount = 0;
5114 pSMB->Reserved = 0;
5115 pSMB->Flags = 0;
5116 pSMB->Timeout = 0;
5117 pSMB->Reserved2 = 0;
5118 byte_count = params + 1 /* pad */ ;
5119 pSMB->TotalParameterCount = cpu_to_le16(params);
5120 pSMB->ParameterCount = pSMB->TotalParameterCount;
5121 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005122 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123
5124 pSMB->DataCount = 0;
5125 pSMB->DataOffset = 0;
5126 pSMB->SetupCount = 1;
5127 pSMB->Reserved3 = 0;
5128 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5129 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005130 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 pSMB->ByteCount = cpu_to_le16(byte_count);
5132
5133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5135 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005136 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 } else { /* decode response */
5138 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5139
Jeff Layton820a8032011-05-04 08:05:26 -04005140 if (rc || get_bcc(&pSMBr->hdr) <
5141 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 rc = -EIO; /* bad smb */
5143 else {
5144 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5145 response_data =
Steve French737b7582005-04-28 22:41:06 -07005146 (FILE_SYSTEM_DEVICE_INFO *)
5147 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 data_offset);
5149 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005150 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 }
5152 }
5153 cifs_buf_release(pSMB);
5154
5155 if (rc == -EAGAIN)
5156 goto QFSDeviceRetry;
5157
5158 return rc;
5159}
5160
5161int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005162CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163{
5164/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5165 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5166 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5167 FILE_SYSTEM_UNIX_INFO *response_data;
5168 int rc = 0;
5169 int bytes_returned = 0;
5170 __u16 params, byte_count;
5171
Joe Perchesf96637b2013-05-04 22:12:25 -05005172 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005174 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5175 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 if (rc)
5177 return rc;
5178
5179 params = 2; /* level */
5180 pSMB->TotalDataCount = 0;
5181 pSMB->DataCount = 0;
5182 pSMB->DataOffset = 0;
5183 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005184 /* BB find exact max SMB PDU from sess structure BB */
5185 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 pSMB->MaxSetupCount = 0;
5187 pSMB->Reserved = 0;
5188 pSMB->Flags = 0;
5189 pSMB->Timeout = 0;
5190 pSMB->Reserved2 = 0;
5191 byte_count = params + 1 /* pad */ ;
5192 pSMB->ParameterCount = cpu_to_le16(params);
5193 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005194 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5195 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 pSMB->SetupCount = 1;
5197 pSMB->Reserved3 = 0;
5198 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5199 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005200 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 pSMB->ByteCount = cpu_to_le16(byte_count);
5202
5203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5205 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005206 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 } else { /* decode response */
5208 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5209
Jeff Layton820a8032011-05-04 08:05:26 -04005210 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 rc = -EIO; /* bad smb */
5212 } else {
5213 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5214 response_data =
5215 (FILE_SYSTEM_UNIX_INFO
5216 *) (((char *) &pSMBr->hdr.Protocol) +
5217 data_offset);
5218 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005219 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 }
5221 }
5222 cifs_buf_release(pSMB);
5223
5224 if (rc == -EAGAIN)
5225 goto QFSUnixRetry;
5226
5227
5228 return rc;
5229}
5230
Jeremy Allisonac670552005-06-22 17:26:35 -07005231int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005232CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005233{
5234/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5235 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5236 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5237 int rc = 0;
5238 int bytes_returned = 0;
5239 __u16 params, param_offset, offset, byte_count;
5240
Joe Perchesf96637b2013-05-04 22:12:25 -05005241 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005242SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005243 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005244 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5245 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005246 if (rc)
5247 return rc;
5248
5249 params = 4; /* 2 bytes zero followed by info level. */
5250 pSMB->MaxSetupCount = 0;
5251 pSMB->Reserved = 0;
5252 pSMB->Flags = 0;
5253 pSMB->Timeout = 0;
5254 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005255 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5256 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005257 offset = param_offset + params;
5258
5259 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005260 /* BB find exact max SMB PDU from sess structure BB */
5261 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005262 pSMB->SetupCount = 1;
5263 pSMB->Reserved3 = 0;
5264 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5265 byte_count = 1 /* pad */ + params + 12;
5266
5267 pSMB->DataCount = cpu_to_le16(12);
5268 pSMB->ParameterCount = cpu_to_le16(params);
5269 pSMB->TotalDataCount = pSMB->DataCount;
5270 pSMB->TotalParameterCount = pSMB->ParameterCount;
5271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5272 pSMB->DataOffset = cpu_to_le16(offset);
5273
5274 /* Params. */
5275 pSMB->FileNum = 0;
5276 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5277
5278 /* Data. */
5279 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5280 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5281 pSMB->ClientUnixCap = cpu_to_le64(cap);
5282
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005283 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005284 pSMB->ByteCount = cpu_to_le16(byte_count);
5285
5286 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5287 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5288 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005289 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005290 } else { /* decode response */
5291 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005292 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005293 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005294 }
5295 cifs_buf_release(pSMB);
5296
5297 if (rc == -EAGAIN)
5298 goto SETFSUnixRetry;
5299
5300 return rc;
5301}
5302
5303
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304
5305int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005306CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005307 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308{
5309/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5310 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5311 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5312 FILE_SYSTEM_POSIX_INFO *response_data;
5313 int rc = 0;
5314 int bytes_returned = 0;
5315 __u16 params, byte_count;
5316
Joe Perchesf96637b2013-05-04 22:12:25 -05005317 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318QFSPosixRetry:
5319 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5320 (void **) &pSMBr);
5321 if (rc)
5322 return rc;
5323
5324 params = 2; /* level */
5325 pSMB->TotalDataCount = 0;
5326 pSMB->DataCount = 0;
5327 pSMB->DataOffset = 0;
5328 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005329 /* BB find exact max SMB PDU from sess structure BB */
5330 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 pSMB->MaxSetupCount = 0;
5332 pSMB->Reserved = 0;
5333 pSMB->Flags = 0;
5334 pSMB->Timeout = 0;
5335 pSMB->Reserved2 = 0;
5336 byte_count = params + 1 /* pad */ ;
5337 pSMB->ParameterCount = cpu_to_le16(params);
5338 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005339 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5340 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 pSMB->SetupCount = 1;
5342 pSMB->Reserved3 = 0;
5343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5344 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005345 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 pSMB->ByteCount = cpu_to_le16(byte_count);
5347
5348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5350 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005351 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 } else { /* decode response */
5353 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5354
Jeff Layton820a8032011-05-04 08:05:26 -04005355 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 rc = -EIO; /* bad smb */
5357 } else {
5358 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5359 response_data =
5360 (FILE_SYSTEM_POSIX_INFO
5361 *) (((char *) &pSMBr->hdr.Protocol) +
5362 data_offset);
5363 FSData->f_bsize =
5364 le32_to_cpu(response_data->BlockSize);
5365 FSData->f_blocks =
5366 le64_to_cpu(response_data->TotalBlocks);
5367 FSData->f_bfree =
5368 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005369 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 FSData->f_bavail = FSData->f_bfree;
5371 } else {
5372 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005373 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 }
Steve French790fe572007-07-07 19:25:05 +00005375 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005377 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005378 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005380 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 }
5382 }
5383 cifs_buf_release(pSMB);
5384
5385 if (rc == -EAGAIN)
5386 goto QFSPosixRetry;
5387
5388 return rc;
5389}
5390
5391
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005392/*
5393 * We can not use write of zero bytes trick to set file size due to need for
5394 * large file support. Also note that this SetPathInfo is preferred to
5395 * SetFileInfo based method in next routine which is only needed to work around
5396 * a sharing violation bugin Samba which this routine can run into.
5397 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005399CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005400 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5401 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402{
5403 struct smb_com_transaction2_spi_req *pSMB = NULL;
5404 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5405 struct file_end_of_file_info *parm_data;
5406 int name_len;
5407 int rc = 0;
5408 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005409 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5410
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 __u16 params, byte_count, data_count, param_offset, offset;
5412
Joe Perchesf96637b2013-05-04 22:12:25 -05005413 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414SetEOFRetry:
5415 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5416 (void **) &pSMBr);
5417 if (rc)
5418 return rc;
5419
5420 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5421 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005422 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5423 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 name_len++; /* trailing null */
5425 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005426 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005427 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005429 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 }
5431 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005432 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005434 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 pSMB->MaxSetupCount = 0;
5436 pSMB->Reserved = 0;
5437 pSMB->Flags = 0;
5438 pSMB->Timeout = 0;
5439 pSMB->Reserved2 = 0;
5440 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005441 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005443 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005444 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5445 pSMB->InformationLevel =
5446 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5447 else
5448 pSMB->InformationLevel =
5449 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5450 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5452 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005453 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 else
5455 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005456 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 }
5458
5459 parm_data =
5460 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5461 offset);
5462 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5463 pSMB->DataOffset = cpu_to_le16(offset);
5464 pSMB->SetupCount = 1;
5465 pSMB->Reserved3 = 0;
5466 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5467 byte_count = 3 /* pad */ + params + data_count;
5468 pSMB->DataCount = cpu_to_le16(data_count);
5469 pSMB->TotalDataCount = pSMB->DataCount;
5470 pSMB->ParameterCount = cpu_to_le16(params);
5471 pSMB->TotalParameterCount = pSMB->ParameterCount;
5472 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005473 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 parm_data->FileSize = cpu_to_le64(size);
5475 pSMB->ByteCount = cpu_to_le16(byte_count);
5476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5477 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005478 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005479 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
5481 cifs_buf_release(pSMB);
5482
5483 if (rc == -EAGAIN)
5484 goto SetEOFRetry;
5485
5486 return rc;
5487}
5488
5489int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005490CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5491 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492{
5493 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 struct file_end_of_file_info *parm_data;
5495 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 __u16 params, param_offset, offset, byte_count, count;
5497
Joe Perchesf96637b2013-05-04 22:12:25 -05005498 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5499 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005500 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5501
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 if (rc)
5503 return rc;
5504
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005505 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5506 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005507
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 params = 6;
5509 pSMB->MaxSetupCount = 0;
5510 pSMB->Reserved = 0;
5511 pSMB->Flags = 0;
5512 pSMB->Timeout = 0;
5513 pSMB->Reserved2 = 0;
5514 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5515 offset = param_offset + params;
5516
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 count = sizeof(struct file_end_of_file_info);
5518 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005519 /* BB find exact max SMB PDU from sess structure BB */
5520 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 pSMB->SetupCount = 1;
5522 pSMB->Reserved3 = 0;
5523 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5524 byte_count = 3 /* pad */ + params + count;
5525 pSMB->DataCount = cpu_to_le16(count);
5526 pSMB->ParameterCount = cpu_to_le16(params);
5527 pSMB->TotalDataCount = pSMB->DataCount;
5528 pSMB->TotalParameterCount = pSMB->ParameterCount;
5529 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5530 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005531 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5532 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 pSMB->DataOffset = cpu_to_le16(offset);
5534 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005535 pSMB->Fid = cfile->fid.netfid;
5536 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5538 pSMB->InformationLevel =
5539 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5540 else
5541 pSMB->InformationLevel =
5542 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005543 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5545 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005546 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 else
5548 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005549 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 }
5551 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005552 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005554 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005556 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5557 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 }
5559
Steve French50c2f752007-07-13 00:33:32 +00005560 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 since file handle passed in no longer valid */
5562
5563 return rc;
5564}
5565
Steve French50c2f752007-07-13 00:33:32 +00005566/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 an open handle, rather than by pathname - this is awkward due to
5568 potential access conflicts on the open, but it is unavoidable for these
5569 old servers since the only other choice is to go from 100 nanosecond DCE
5570 time and resort to the original setpathinfo level which takes the ancient
5571 DOS time format with 2 second granularity */
5572int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005573CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005574 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575{
5576 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 char *data_offset;
5578 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 __u16 params, param_offset, offset, byte_count, count;
5580
Joe Perchesf96637b2013-05-04 22:12:25 -05005581 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005582 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5583
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 if (rc)
5585 return rc;
5586
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005587 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5588 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005589
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 params = 6;
5591 pSMB->MaxSetupCount = 0;
5592 pSMB->Reserved = 0;
5593 pSMB->Flags = 0;
5594 pSMB->Timeout = 0;
5595 pSMB->Reserved2 = 0;
5596 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5597 offset = param_offset + params;
5598
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005599 data_offset = (char *)pSMB +
5600 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601
Steve French26f57362007-08-30 22:09:15 +00005602 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005604 /* BB find max SMB PDU from sess */
5605 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 pSMB->SetupCount = 1;
5607 pSMB->Reserved3 = 0;
5608 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5609 byte_count = 3 /* pad */ + params + count;
5610 pSMB->DataCount = cpu_to_le16(count);
5611 pSMB->ParameterCount = cpu_to_le16(params);
5612 pSMB->TotalDataCount = pSMB->DataCount;
5613 pSMB->TotalParameterCount = pSMB->ParameterCount;
5614 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5615 pSMB->DataOffset = cpu_to_le16(offset);
5616 pSMB->Fid = fid;
5617 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5618 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5619 else
5620 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5621 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005622 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005624 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005625 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005626 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005627 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5628 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629
Steve French50c2f752007-07-13 00:33:32 +00005630 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 since file handle passed in no longer valid */
5632
5633 return rc;
5634}
5635
Jeff Layton6d22f092008-09-23 11:48:35 -04005636int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005637CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005638 bool delete_file, __u16 fid, __u32 pid_of_opener)
5639{
5640 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5641 char *data_offset;
5642 int rc = 0;
5643 __u16 params, param_offset, offset, byte_count, count;
5644
Joe Perchesf96637b2013-05-04 22:12:25 -05005645 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005646 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5647
5648 if (rc)
5649 return rc;
5650
5651 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5652 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5653
5654 params = 6;
5655 pSMB->MaxSetupCount = 0;
5656 pSMB->Reserved = 0;
5657 pSMB->Flags = 0;
5658 pSMB->Timeout = 0;
5659 pSMB->Reserved2 = 0;
5660 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5661 offset = param_offset + params;
5662
5663 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5664
5665 count = 1;
5666 pSMB->MaxParameterCount = cpu_to_le16(2);
5667 /* BB find max SMB PDU from sess */
5668 pSMB->MaxDataCount = cpu_to_le16(1000);
5669 pSMB->SetupCount = 1;
5670 pSMB->Reserved3 = 0;
5671 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5672 byte_count = 3 /* pad */ + params + count;
5673 pSMB->DataCount = cpu_to_le16(count);
5674 pSMB->ParameterCount = cpu_to_le16(params);
5675 pSMB->TotalDataCount = pSMB->DataCount;
5676 pSMB->TotalParameterCount = pSMB->ParameterCount;
5677 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5678 pSMB->DataOffset = cpu_to_le16(offset);
5679 pSMB->Fid = fid;
5680 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5681 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005682 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005683 pSMB->ByteCount = cpu_to_le16(byte_count);
5684 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005685 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005686 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005687 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005688
5689 return rc;
5690}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691
5692int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005693CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005694 const char *fileName, const FILE_BASIC_INFO *data,
5695 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696{
5697 TRANSACTION2_SPI_REQ *pSMB = NULL;
5698 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5699 int name_len;
5700 int rc = 0;
5701 int bytes_returned = 0;
5702 char *data_offset;
5703 __u16 params, param_offset, offset, byte_count, count;
5704
Joe Perchesf96637b2013-05-04 22:12:25 -05005705 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706
5707SetTimesRetry:
5708 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5709 (void **) &pSMBr);
5710 if (rc)
5711 return rc;
5712
5713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5714 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005715 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5716 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 name_len++; /* trailing null */
5718 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005719 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 name_len = strnlen(fileName, PATH_MAX);
5721 name_len++; /* trailing null */
5722 strncpy(pSMB->FileName, fileName, name_len);
5723 }
5724
5725 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005726 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005728 /* BB find max SMB PDU from sess structure BB */
5729 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 pSMB->MaxSetupCount = 0;
5731 pSMB->Reserved = 0;
5732 pSMB->Flags = 0;
5733 pSMB->Timeout = 0;
5734 pSMB->Reserved2 = 0;
5735 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005736 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 offset = param_offset + params;
5738 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5739 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5740 pSMB->DataOffset = cpu_to_le16(offset);
5741 pSMB->SetupCount = 1;
5742 pSMB->Reserved3 = 0;
5743 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5744 byte_count = 3 /* pad */ + params + count;
5745
5746 pSMB->DataCount = cpu_to_le16(count);
5747 pSMB->ParameterCount = cpu_to_le16(params);
5748 pSMB->TotalDataCount = pSMB->DataCount;
5749 pSMB->TotalParameterCount = pSMB->ParameterCount;
5750 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5751 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5752 else
5753 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5754 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005755 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005756 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 pSMB->ByteCount = cpu_to_le16(byte_count);
5758 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5759 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005760 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005761 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
5763 cifs_buf_release(pSMB);
5764
5765 if (rc == -EAGAIN)
5766 goto SetTimesRetry;
5767
5768 return rc;
5769}
5770
5771/* Can not be used to set time stamps yet (due to old DOS time format) */
5772/* Can be used to set attributes */
5773#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5774 handling it anyway and NT4 was what we thought it would be needed for
5775 Do not delete it until we prove whether needed for Win9x though */
5776int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005777CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 __u16 dos_attrs, const struct nls_table *nls_codepage)
5779{
5780 SETATTR_REQ *pSMB = NULL;
5781 SETATTR_RSP *pSMBr = NULL;
5782 int rc = 0;
5783 int bytes_returned;
5784 int name_len;
5785
Joe Perchesf96637b2013-05-04 22:12:25 -05005786 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787
5788SetAttrLgcyRetry:
5789 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5790 (void **) &pSMBr);
5791 if (rc)
5792 return rc;
5793
5794 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5795 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005796 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5797 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 name_len++; /* trailing null */
5799 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005800 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 name_len = strnlen(fileName, PATH_MAX);
5802 name_len++; /* trailing null */
5803 strncpy(pSMB->fileName, fileName, name_len);
5804 }
5805 pSMB->attr = cpu_to_le16(dos_attrs);
5806 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005807 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5809 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005811 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005812 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813
5814 cifs_buf_release(pSMB);
5815
5816 if (rc == -EAGAIN)
5817 goto SetAttrLgcyRetry;
5818
5819 return rc;
5820}
5821#endif /* temporarily unneeded SetAttr legacy function */
5822
Jeff Layton654cf142009-07-09 20:02:49 -04005823static void
5824cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5825 const struct cifs_unix_set_info_args *args)
5826{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005827 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005828 u64 mode = args->mode;
5829
Eric W. Biederman49418b22013-02-06 00:57:56 -08005830 if (uid_valid(args->uid))
5831 uid = from_kuid(&init_user_ns, args->uid);
5832 if (gid_valid(args->gid))
5833 gid = from_kgid(&init_user_ns, args->gid);
5834
Jeff Layton654cf142009-07-09 20:02:49 -04005835 /*
5836 * Samba server ignores set of file size to zero due to bugs in some
5837 * older clients, but we should be precise - we use SetFileSize to
5838 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005839 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005840 * zero instead of -1 here
5841 */
5842 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5843 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5844 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5845 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5846 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005847 data_offset->Uid = cpu_to_le64(uid);
5848 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005849 /* better to leave device as zero when it is */
5850 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5851 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5852 data_offset->Permissions = cpu_to_le64(mode);
5853
5854 if (S_ISREG(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_FILE);
5856 else if (S_ISDIR(mode))
5857 data_offset->Type = cpu_to_le32(UNIX_DIR);
5858 else if (S_ISLNK(mode))
5859 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5860 else if (S_ISCHR(mode))
5861 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5862 else if (S_ISBLK(mode))
5863 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5864 else if (S_ISFIFO(mode))
5865 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5866 else if (S_ISSOCK(mode))
5867 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5868}
5869
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005871CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005872 const struct cifs_unix_set_info_args *args,
5873 u16 fid, u32 pid_of_opener)
5874{
5875 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005876 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005877 int rc = 0;
5878 u16 params, param_offset, offset, byte_count, count;
5879
Joe Perchesf96637b2013-05-04 22:12:25 -05005880 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005881 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5882
5883 if (rc)
5884 return rc;
5885
5886 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5887 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5888
5889 params = 6;
5890 pSMB->MaxSetupCount = 0;
5891 pSMB->Reserved = 0;
5892 pSMB->Flags = 0;
5893 pSMB->Timeout = 0;
5894 pSMB->Reserved2 = 0;
5895 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5896 offset = param_offset + params;
5897
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005898 data_offset = (char *)pSMB +
5899 offsetof(struct smb_hdr, Protocol) + offset;
5900
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005901 count = sizeof(FILE_UNIX_BASIC_INFO);
5902
5903 pSMB->MaxParameterCount = cpu_to_le16(2);
5904 /* BB find max SMB PDU from sess */
5905 pSMB->MaxDataCount = cpu_to_le16(1000);
5906 pSMB->SetupCount = 1;
5907 pSMB->Reserved3 = 0;
5908 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5909 byte_count = 3 /* pad */ + params + count;
5910 pSMB->DataCount = cpu_to_le16(count);
5911 pSMB->ParameterCount = cpu_to_le16(params);
5912 pSMB->TotalDataCount = pSMB->DataCount;
5913 pSMB->TotalParameterCount = pSMB->ParameterCount;
5914 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5915 pSMB->DataOffset = cpu_to_le16(offset);
5916 pSMB->Fid = fid;
5917 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5918 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005919 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005920 pSMB->ByteCount = cpu_to_le16(byte_count);
5921
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005922 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005923
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005924 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005925 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005926 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5927 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005928
5929 /* Note: On -EAGAIN error only caller can retry on handle based calls
5930 since file handle passed in no longer valid */
5931
5932 return rc;
5933}
5934
5935int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005936CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005937 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005938 const struct cifs_unix_set_info_args *args,
5939 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940{
5941 TRANSACTION2_SPI_REQ *pSMB = NULL;
5942 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5943 int name_len;
5944 int rc = 0;
5945 int bytes_returned = 0;
5946 FILE_UNIX_BASIC_INFO *data_offset;
5947 __u16 params, param_offset, offset, count, byte_count;
5948
Joe Perchesf96637b2013-05-04 22:12:25 -05005949 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950setPermsRetry:
5951 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5952 (void **) &pSMBr);
5953 if (rc)
5954 return rc;
5955
5956 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5957 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005958 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005959 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 name_len++; /* trailing null */
5961 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005962 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005963 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005965 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 }
5967
5968 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005969 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005971 /* BB find max SMB PDU from sess structure BB */
5972 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 pSMB->MaxSetupCount = 0;
5974 pSMB->Reserved = 0;
5975 pSMB->Flags = 0;
5976 pSMB->Timeout = 0;
5977 pSMB->Reserved2 = 0;
5978 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005979 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 offset = param_offset + params;
5981 data_offset =
5982 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5983 offset);
5984 memset(data_offset, 0, count);
5985 pSMB->DataOffset = cpu_to_le16(offset);
5986 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5987 pSMB->SetupCount = 1;
5988 pSMB->Reserved3 = 0;
5989 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5990 byte_count = 3 /* pad */ + params + count;
5991 pSMB->ParameterCount = cpu_to_le16(params);
5992 pSMB->DataCount = cpu_to_le16(count);
5993 pSMB->TotalParameterCount = pSMB->ParameterCount;
5994 pSMB->TotalDataCount = pSMB->DataCount;
5995 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5996 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005997 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005998
Jeff Layton654cf142009-07-09 20:02:49 -04005999 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000
6001 pSMB->ByteCount = cpu_to_le16(byte_count);
6002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006004 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006005 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006
Steve French0d817bc2008-05-22 02:02:03 +00006007 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008 if (rc == -EAGAIN)
6009 goto setPermsRetry;
6010 return rc;
6011}
6012
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006014/*
6015 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6016 * function used by listxattr and getxattr type calls. When ea_name is set,
6017 * it looks for that attribute name and stuffs that value into the EAData
6018 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6019 * buffer. In both cases, the return value is either the length of the
6020 * resulting data or a negative error code. If EAData is a NULL pointer then
6021 * the data isn't copied to it, but the length is returned.
6022 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006024CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006025 const unsigned char *searchName, const unsigned char *ea_name,
6026 char *EAData, size_t buf_size,
6027 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028{
6029 /* BB assumes one setup word */
6030 TRANSACTION2_QPI_REQ *pSMB = NULL;
6031 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6032 int rc = 0;
6033 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006034 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006035 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006036 struct fea *temp_fea;
6037 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006038 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006039 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006040 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041
Joe Perchesf96637b2013-05-04 22:12:25 -05006042 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043QAllEAsRetry:
6044 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6045 (void **) &pSMBr);
6046 if (rc)
6047 return rc;
6048
6049 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006050 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006051 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6052 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006053 list_len++; /* trailing null */
6054 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006056 list_len = strnlen(searchName, PATH_MAX);
6057 list_len++; /* trailing null */
6058 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 }
6060
Jeff Layton6e462b92010-02-10 16:18:26 -05006061 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062 pSMB->TotalDataCount = 0;
6063 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006064 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006065 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 pSMB->MaxSetupCount = 0;
6067 pSMB->Reserved = 0;
6068 pSMB->Flags = 0;
6069 pSMB->Timeout = 0;
6070 pSMB->Reserved2 = 0;
6071 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006072 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073 pSMB->DataCount = 0;
6074 pSMB->DataOffset = 0;
6075 pSMB->SetupCount = 1;
6076 pSMB->Reserved3 = 0;
6077 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6078 byte_count = params + 1 /* pad */ ;
6079 pSMB->TotalParameterCount = cpu_to_le16(params);
6080 pSMB->ParameterCount = pSMB->TotalParameterCount;
6081 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6082 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006083 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084 pSMB->ByteCount = cpu_to_le16(byte_count);
6085
6086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6088 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006089 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006090 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006092
6093
6094 /* BB also check enough total bytes returned */
6095 /* BB we need to improve the validity checking
6096 of these trans2 responses */
6097
6098 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006099 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006100 rc = -EIO; /* bad smb */
6101 goto QAllEAsOut;
6102 }
6103
6104 /* check that length of list is not more than bcc */
6105 /* check that each entry does not go beyond length
6106 of list */
6107 /* check that each element of each entry does not
6108 go beyond end of list */
6109 /* validate_trans2_offsets() */
6110 /* BB check if start of smb + data_offset > &bcc+ bcc */
6111
6112 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6113 ea_response_data = (struct fealist *)
6114 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6115
Jeff Layton6e462b92010-02-10 16:18:26 -05006116 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006117 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006118 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006119 cifs_dbg(FYI, "empty EA list returned from server\n");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006120 goto QAllEAsOut;
6121 }
6122
Jeff Layton0cd126b2010-02-10 16:18:26 -05006123 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006124 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006125 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006126 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006127 rc = -EIO;
6128 goto QAllEAsOut;
6129 }
6130
Jeff Laytonf0d38682010-02-10 16:18:26 -05006131 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006132 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006133 temp_fea = ea_response_data->list;
6134 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006135 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006136 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006137 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006138
Jeff Layton6e462b92010-02-10 16:18:26 -05006139 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006140 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006141 /* make sure we can read name_len and value_len */
6142 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006143 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006144 rc = -EIO;
6145 goto QAllEAsOut;
6146 }
6147
6148 name_len = temp_fea->name_len;
6149 value_len = le16_to_cpu(temp_fea->value_len);
6150 list_len -= name_len + 1 + value_len;
6151 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006152 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006153 rc = -EIO;
6154 goto QAllEAsOut;
6155 }
6156
Jeff Layton31c05192010-02-10 16:18:26 -05006157 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006158 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006159 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006160 temp_ptr += name_len + 1;
6161 rc = value_len;
6162 if (buf_size == 0)
6163 goto QAllEAsOut;
6164 if ((size_t)value_len > buf_size) {
6165 rc = -ERANGE;
6166 goto QAllEAsOut;
6167 }
6168 memcpy(EAData, temp_ptr, value_len);
6169 goto QAllEAsOut;
6170 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006171 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006172 /* account for prefix user. and trailing null */
6173 rc += (5 + 1 + name_len);
6174 if (rc < (int) buf_size) {
6175 memcpy(EAData, "user.", 5);
6176 EAData += 5;
6177 memcpy(EAData, temp_ptr, name_len);
6178 EAData += name_len;
6179 /* null terminate name */
6180 *EAData = 0;
6181 ++EAData;
6182 } else if (buf_size == 0) {
6183 /* skip copy - calc size only */
6184 } else {
6185 /* stop before overrun buffer */
6186 rc = -ERANGE;
6187 break;
6188 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006189 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006190 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006191 temp_fea = (struct fea *)temp_ptr;
6192 }
6193
Jeff Layton31c05192010-02-10 16:18:26 -05006194 /* didn't find the named attribute */
6195 if (ea_name)
6196 rc = -ENODATA;
6197
Jeff Laytonf0d38682010-02-10 16:18:26 -05006198QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006199 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 if (rc == -EAGAIN)
6201 goto QAllEAsRetry;
6202
6203 return (ssize_t)rc;
6204}
6205
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006207CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6208 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006209 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6210 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211{
6212 struct smb_com_transaction2_spi_req *pSMB = NULL;
6213 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6214 struct fealist *parm_data;
6215 int name_len;
6216 int rc = 0;
6217 int bytes_returned = 0;
6218 __u16 params, param_offset, byte_count, offset, count;
6219
Joe Perchesf96637b2013-05-04 22:12:25 -05006220 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221SetEARetry:
6222 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6223 (void **) &pSMBr);
6224 if (rc)
6225 return rc;
6226
6227 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6228 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006229 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6230 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231 name_len++; /* trailing null */
6232 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006233 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234 name_len = strnlen(fileName, PATH_MAX);
6235 name_len++; /* trailing null */
6236 strncpy(pSMB->FileName, fileName, name_len);
6237 }
6238
6239 params = 6 + name_len;
6240
6241 /* done calculating parms using name_len of file name,
6242 now use name_len to calculate length of ea name
6243 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006244 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 name_len = 0;
6246 else
Steve French50c2f752007-07-13 00:33:32 +00006247 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006249 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006251 /* BB find max SMB PDU from sess */
6252 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 pSMB->MaxSetupCount = 0;
6254 pSMB->Reserved = 0;
6255 pSMB->Flags = 0;
6256 pSMB->Timeout = 0;
6257 pSMB->Reserved2 = 0;
6258 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006259 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 offset = param_offset + params;
6261 pSMB->InformationLevel =
6262 cpu_to_le16(SMB_SET_FILE_EA);
6263
6264 parm_data =
6265 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6266 offset);
6267 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6268 pSMB->DataOffset = cpu_to_le16(offset);
6269 pSMB->SetupCount = 1;
6270 pSMB->Reserved3 = 0;
6271 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6272 byte_count = 3 /* pad */ + params + count;
6273 pSMB->DataCount = cpu_to_le16(count);
6274 parm_data->list_len = cpu_to_le32(count);
6275 parm_data->list[0].EA_flags = 0;
6276 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006277 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006279 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006280 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281 parm_data->list[0].name[name_len] = 0;
6282 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6283 /* caller ensures that ea_value_len is less than 64K but
6284 we need to ensure that it fits within the smb */
6285
Steve French50c2f752007-07-13 00:33:32 +00006286 /*BB add length check to see if it would fit in
6287 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006288 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6289 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006290 memcpy(parm_data->list[0].name+name_len+1,
6291 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292
6293 pSMB->TotalDataCount = pSMB->DataCount;
6294 pSMB->ParameterCount = cpu_to_le16(params);
6295 pSMB->TotalParameterCount = pSMB->ParameterCount;
6296 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006297 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298 pSMB->ByteCount = cpu_to_le16(byte_count);
6299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006301 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006302 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
6304 cifs_buf_release(pSMB);
6305
6306 if (rc == -EAGAIN)
6307 goto SetEARetry;
6308
6309 return rc;
6310}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311#endif
Steve French0eff0e22011-02-24 05:39:23 +00006312
6313#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6314/*
6315 * Years ago the kernel added a "dnotify" function for Samba server,
6316 * to allow network clients (such as Windows) to display updated
6317 * lists of files in directory listings automatically when
6318 * files are added by one user when another user has the
6319 * same directory open on their desktop. The Linux cifs kernel
6320 * client hooked into the kernel side of this interface for
6321 * the same reason, but ironically when the VFS moved from
6322 * "dnotify" to "inotify" it became harder to plug in Linux
6323 * network file system clients (the most obvious use case
6324 * for notify interfaces is when multiple users can update
6325 * the contents of the same directory - exactly what network
6326 * file systems can do) although the server (Samba) could
6327 * still use it. For the short term we leave the worker
6328 * function ifdeffed out (below) until inotify is fixed
6329 * in the VFS to make it easier to plug in network file
6330 * system clients. If inotify turns out to be permanently
6331 * incompatible for network fs clients, we could instead simply
6332 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6333 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006334int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006335 const int notify_subdirs, const __u16 netfid,
6336 __u32 filter, struct file *pfile, int multishot,
6337 const struct nls_table *nls_codepage)
6338{
6339 int rc = 0;
6340 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6341 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6342 struct dir_notify_req *dnotify_req;
6343 int bytes_returned;
6344
Joe Perchesf96637b2013-05-04 22:12:25 -05006345 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006346 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6347 (void **) &pSMBr);
6348 if (rc)
6349 return rc;
6350
6351 pSMB->TotalParameterCount = 0 ;
6352 pSMB->TotalDataCount = 0;
6353 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006354 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006355 pSMB->MaxSetupCount = 4;
6356 pSMB->Reserved = 0;
6357 pSMB->ParameterOffset = 0;
6358 pSMB->DataCount = 0;
6359 pSMB->DataOffset = 0;
6360 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6361 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6362 pSMB->ParameterCount = pSMB->TotalParameterCount;
6363 if (notify_subdirs)
6364 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6365 pSMB->Reserved2 = 0;
6366 pSMB->CompletionFilter = cpu_to_le32(filter);
6367 pSMB->Fid = netfid; /* file handle always le */
6368 pSMB->ByteCount = 0;
6369
6370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6371 (struct smb_hdr *)pSMBr, &bytes_returned,
6372 CIFS_ASYNC_OP);
6373 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006374 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006375 } else {
6376 /* Add file to outstanding requests */
6377 /* BB change to kmem cache alloc */
6378 dnotify_req = kmalloc(
6379 sizeof(struct dir_notify_req),
6380 GFP_KERNEL);
6381 if (dnotify_req) {
6382 dnotify_req->Pid = pSMB->hdr.Pid;
6383 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6384 dnotify_req->Mid = pSMB->hdr.Mid;
6385 dnotify_req->Tid = pSMB->hdr.Tid;
6386 dnotify_req->Uid = pSMB->hdr.Uid;
6387 dnotify_req->netfid = netfid;
6388 dnotify_req->pfile = pfile;
6389 dnotify_req->filter = filter;
6390 dnotify_req->multishot = multishot;
6391 spin_lock(&GlobalMid_Lock);
6392 list_add_tail(&dnotify_req->lhead,
6393 &GlobalDnotifyReqList);
6394 spin_unlock(&GlobalMid_Lock);
6395 } else
6396 rc = -ENOMEM;
6397 }
6398 cifs_buf_release(pSMB);
6399 return rc;
6400}
6401#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */